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-starterorg.springframework.boot spring-boot-configuration-processortrue 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 FilterRegistrationBeanloggingFilterFilterRegistrationBean(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); // 这一步 获取配置候选 的类名 Listconfigurations = 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 ListgetCandidateConfigurations(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"; ... }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)