springboot-自定义starter

在实际业务开发过程当中,有很多公共的功能。针对这些功能,可以自己开发公共的starter模块

命名

对于自己开发的starter模块,一般使用xxx-spring-boot-starter,而spring自己生态圈的starter,一般都是spring-boot-starter-xxx格式命名

maven依赖(pom.xml)

	<!-- 版本自己定 -->
	<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
    </dependencies>

属性类

package com.leewan.vue.starter.properties;

import org.springframework.boot.context.properties.ConfigurationProperties;


@ConfigurationProperties(prefix = "leewan.vue")
public class LeewanVueProperties {

    private String rootPath;

    public String getRootPath() {
        return rootPath;
    }

    public void setRootPath(String rootPath) {
        this.rootPath = rootPath;
    }
}

通过@ConfigurationProperties注解,注入属性

配置类(最核心)

package com.leewan.vue.starter.config;

import com.leewan.vue.starter.condition.ConditionalHasProperties;
import com.leewan.vue.starter.controller.LeewanPageController;
import com.leewan.vue.starter.pageContext.ClassPathPageContext;
import com.leewan.vue.starter.pageContext.FilePageContext;
import com.leewan.vue.starter.pageContext.PageContext;
import com.leewan.vue.starter.properties.LeewanVueProperties;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ResourceUtils;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.lang.reflect.Method;
import java.net.URL;

@Configuration
//开启LeewanVueProperties配置对象,如不配置,则无法自动注入LeewanVueProperties类
@EnableConfigurationProperties(LeewanVueProperties.class)
//条件注解  
@ConditionalHasProperties(propertyName = "leewan.vue.root-path")
public class LeewanVueConfiguration {

    @Autowired
    private LeewanVueProperties properties;


    @Bean
    public PageContext pageContext() {
        String rootPath = properties.getRootPath();
        if(rootPath.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX)) {
            String path = rootPath.substring(ResourceUtils.CLASSPATH_URL_PREFIX.length());
            URL url = Thread.currentThread().getContextClassLoader().getResource(path);
            if(ResourceUtils.isJarURL(url)) {
                return new ClassPathPageContext(path);
            }else {
                return new FilePageContext(rootPath);
            }
        }else {
            return new FilePageContext(rootPath);
        }
    }

    @Bean("leewanPageController")
    public LeewanPageController pageController(){
        return new LeewanPageController();
    }

    @Bean
    public ApplicationContextAware aware(){
        return new ApplicationContextAware() {
            @Override
            public void setApplicationContext(ApplicationContext application) throws BeansException {
                //手动注册controller
                RequestMappingHandlerMapping handlerMapping = application.getBean(RequestMappingHandlerMapping.class);

                try {
                    Method method=handlerMapping.getClass().getSuperclass().getSuperclass().
                            getDeclaredMethod("detectHandlerMethods",Object.class);
                    method.setAccessible(true);
                    method.invoke(handlerMapping, "leewanPageController");
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        };
    }

}


@EnableConfigurationProperties(LeewanVueProperties.class)

表示开启LeewanVueProperties配置对象,否则无法注入LeewanVueProperties对象

后续使用IDE(如idea,eclipse)编辑yml文件时,会根据LeewanVueProperties进行自动提示

条件注解

有些starter虽然引入,但实际运行过程中 需要满足一些特定条件才会运行。所以还需要条件注解来进行判断。springboot自带了很多条件注解,如@ConditionalOnProperty、@ConditionalOnBean等。

但是对于一些比较复杂的业务场景,使用spring自带的条件注解无法满足需求时,我们还可以自定义注解。 自定义注解一般需要两个类,一是注解,一是具体的条件匹配实现类

注解类
package com.leewan.vue.starter.condition;

import org.springframework.context.annotation.Conditional;

//配置条件匹配类
@Conditional(HasPropertiesCondition.class)
public @interface ConditionalHasProperties {

    String propertyName() default "";

}
条件匹配实现类

需要实现org.springframework.context.annotation.Condition类,
通过AnnotatedTypeMetadata可以获取注解类里的一些配置
通过conditionContext可以获取上下文一些配置参数

package com.leewan.vue.starter.condition;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.util.StringUtils;

import java.util.Map;


public class HasPropertiesCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        Map<String, Object> annotationAttributes = annotatedTypeMetadata.getAnnotationAttributes(ConditionalHasProperties.class.getName());
        String propertyName = (String) annotationAttributes.get("propertyName");
        String property = conditionContext.getEnvironment().getProperty(propertyName);

        if(StringUtils.hasText(property)){
            return true;
        }
        return false;
    }
}

配置文件

最后需要告诉spring 你的这个starter的自动配置类是哪个。通过配置文件进行配置
1、resources目录下 新建META-INF目录
2、新建文件spring.factories
3、在spring.factories中

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.leewan.vue.starter.config.LeewanVueConfiguration

在这里插入图片描述

一切搞定


版权声明:本文为jackycjw原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。