spring-boot-starter自定义

spring-boot-starter自定义,第1张

spring-boot-starter自定义

Spring boot starter 组件有两种方式 @EnableXX 和 autoconfigure 通过spring的spi加载

对于官方组件,是基于condition条件来决定对于类是否要自动装配,对于第三方组件,是采用spi机制来实现扩展

命名规则

官方命名规则 spring-boot-starter-xxx 参考 https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-starters第三方 xxx-spring-boot-starter

Spring boot starter 组件有两种方式

@EnableXX 开关启动模式EnableAutoConfiguration 通过spring的spi加载启动

Spring boot 的注解驱动

Spring 3.x 无配置化方式实现bean的状态 java config 注解 Spring 4.x @Conditional 条件装配Spring 5.x Indexed Spring的动态Bean的装载 @importimportSelector:DeferredimportSelectorRegistator:importBeanDefinintionRegistrar

SpringFactoriesLoader(SPI)
spring.factories

SPI 机制

Service provider interface

满足以下条件

需要在classpath目录下创建一个 meta-INF/services在该目录下创建一个 扩展点的全路径名.

文件中填写这个扩展点的实现文件编码格式UTF-8 ServiceLoader去进行加载

引入的依赖

 
    
     org.springframework.boot
     spring-boot-starter
    
    
    
        org.springframework.boot
        spring-boot-configuration-processor
        true
    
    
        org.springframework.boot
        spring-boot-autoconfigure
    

@EnableXXX 开关的自动配置
案例: smart-logging-spring-boot-starter

EnableSmartLogClient开关配置
EnableSmartLogClient 开关

import org.springframework.context.annotation.import;

import java.lang.annotation.*;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@documented
@import({SmartLoggingConfig.class})
public @interface EnableSmartLogClient {
		
}

Enablexxx开关 主要用了spring的 import的特性,import可以通过下面三种方式项目spring的ioc容器中注入bean

@Configuration 配置类 通过@Bean 注入bean 这个案例就是用了这个机制importSelector 实现类 实现selectimports方法,返回需要注册的bean的类名字符串,ioc通过反射方式注入importBeanDefinitionRegistrar实现类,子类方法中拿到ioc容器registry,手动将注册bean定义

SmartLoggingConfig

// 真正starter组件需要事情的类
public class LoggingFilter  extends OncePerRequestFilter {
    private static Logger logger = LoggerFactory.getLogger(LoggingFilter.class);
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        filterChain.doFilter(request,response);
        logger.info("request-url:"+request.getRequestURI());
    }
}

// 配置类
@Configuration
@EnableConfigurationProperties(SmartLoggingProperties.class)
public class SmartLoggingConfig {
  @Bean
  public LoggingFilter loggingFilter(){
      return new LoggingFilter();
  }
  @Bean
  public FilterRegistrationBean loggingFilterFilterRegistrationBean(SmartLoggingProperties properties){
      FilterRegistrationBean registrationBean = new FilterRegistrationBean<>();
      registrationBean.setFilter(loggingFilter());
      registrationBean.setName("loggingFilter");
      registrationBean.addUrlPatterns("
	Class[] exclude() default {};

	
	String[] excludeName() default {};

}

AutoConfigurationimportSelector
AutoConfigurationimportSelector#selectimport关键代码

public String[] selectimports(Annotationmetadata annotationmetadata) {
		if (!isEnabled(annotationmetadata)) {
			return NO_importS;
		}
    	// 从spring.factories配置文件中获取配置类
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationmetadata);
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

AutoConfigurationimportSelector#getAutoConfigurationEntry

protected AutoConfigurationEntry getAutoConfigurationEntry(Annotationmetadata annotationmetadata) {
		if (!isEnabled(annotationmetadata)) {
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationmetadata);
        // 这一步 获取配置候选 的类名
		List configurations = getCandidateConfigurations(annotationmetadata, attributes);
        // 去重
		configurations = removeDuplicates(configurations);
        // 通过 spring.autoconfigure.exclude 和注解中的exclude属性排除
		Set exclusions = getExclusions(annotationmetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		configurations = getConfigurationClassFilter().filter(configurations);
		fireAutoConfigurationimportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}
protected List getCandidateConfigurations(Annotationmetadata metadata, AnnotationAttributes attributes) {
		List configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
				getBeanClassLoader());
		Assert.notEmpty(configurations, "No auto configuration classes found in meta-INF/spring.factories. If you "
				+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
}
public final class SpringFactoriesLoader {

	
	public static final String FACTORIES_RESOURCE_LOCATION = "meta-INF/spring.factories";
	...
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5708032.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存