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 的实现
@Override
public 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);
}
复制代码
评论