Spring Boot 源码:自动装配
核心注解和接口
@EnableAutoConfiguration
@EnableAutoConfiguration public @interface SpringBootApplication { }
复制代码
@EnableXXX
Spring 3.1.x 开始支持各种 @Enable 注解,作用:把相关组件的 Bean 装配到 IoC 容器,减少代码配置和使用难度。
@Import 是 @Enable 注解的核心,Spring 会解析 @Import 参数,来实现 Bean 的装配
@Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { Class<?>[] exclude() default {}; String[] excludeName() default {}; }
复制代码
AutoConfigurationImportSelector
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered { }
复制代码
ImportSelector
方法表示返回的参数(String[])就是要装配到 IoC 容器的类,**可以实现批量装配,**可以在方式实现中进行更灵活复杂的装配逻辑
public interface ImportSelector { String[] selectImports(AnnotationMetadata importingClassMetadata); }
复制代码
AutoConfigurationImportSelector 的实现
@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) { AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader .loadMetadata(this.beanClassLoader); AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry( autoConfigurationMetadata, annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}
protected AutoConfigurationEntry getAutoConfigurationEntry( AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) { // 获取 exclude\excludeName AnnotationAttributes attributes = getAttributes(annotationMetadata); // 获取所有自动装配的配置类 List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); // 去除重复配置 configurations = removeDuplicates(configurations); // 去除exclude配置 Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = filter(configurations, autoConfigurationMetadata); // 广播装配事件 fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions);}
复制代码
获取所有自动装配的配置类
使用到 SpringFactoriesLoader,扫描 classpath 下的 META-INF/spring.factories 文件
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames( getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); return configurations;}
复制代码
META-INF/spring.factories 文件内容是 KEY=VALUE 格式
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.cloud.netflix.eureka.config.EurekaClientConfigServerAutoConfiguration,\ org.springframework.cloud.netflix.eureka.config.EurekaDiscoveryClientConfigServiceAutoConfiguration,\ org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration,\ org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration,\ org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\ xxxx.xxxxx.xxxListener,\ xxxx.xxxxx.xxxListener,\ xxxx.xxxxx.xxxListener,\
复制代码
loadFactoryNames() 方法根据 KEY 得到 VALUE 值 XXXXConfiguration,就是基于 JavaConfig 的配置类,可以看到很多条件注解
@Configuration @ConditionalOnProperty( value = {"eureka.client.enabled"}, matchIfMissing = true ) @ConditionalOnDiscoveryEnabled public class EurekaClientAutoConfiguration { }
复制代码
广播装配事件
private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) { // 再次用到 SpringFactoriesLoader,获取所有 AutoConfigurationImportListener 实现类,并广播事件 List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners(); if (!listeners.isEmpty()) { AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions); for (AutoConfigurationImportListener listener : listeners) { invokeAwareMethods(listener); listener.onAutoConfigurationImportEvent(event); } }}
protected List<AutoConfigurationImportListener> getAutoConfigurationImportListeners() { return SpringFactoriesLoader.loadFactories(AutoConfigurationImportListener.class, this.beanClassLoader);}
复制代码
评论