1. @SpringBootApplication
1.1 @SpringBootApplication注解
万事开头难,一旦开始就不要停,不要停,不要,直到她说停。
一切从 @SpringBootApplication 注解开始说起,它是一个组合注解,我们先看看源码怎么写的。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
}
@Inherited注解声明注解上时,在类上表明该类具有继承性。子类会自动继承该注解。
需要我们注重关注三个注解:@SpringBootConfiguration、@ComponentScan、@EnableAutoConfiguration
1.1.1 @SpringBootConfiguration
1.1.2 @ComponentScan
1.1.3 @EnableAutoConfiguration
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
在 @EnableAutoConfiguration 注解上使用了 @Import注解导入了一个配置类AutoConfigurationImportSelector,看到这里如果看过前一篇
SpringBoot自动装配原理分析之上篇我想你应该知道AutoConfigurationImportSelector必然是ImportSelector或ImportBeanDefinitionRegistrar的实现类。
2 AutoConfigurationImportSelector
我们可以看到一些信息:
AutoConfigurationImportSelector
它实现了DeferredImportSelector
接口,而DeferredImportSelector
接口继承自ImportSelector
接口;- 实现了
Ordered
接口定义加载顺序的接口;
//从定义上可以看到实现了DeferredImportSelector接口
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
//....略
}
2.1 解读方法#selectImports
小伙伴儿,我们回到AutoConfigurationImportSelector
类中,又要准备深入了,鸡冻不…哈哈
看看方法名,selectImports
选择导入,导入什么,显然就是要自动装配的类。怎么还要选择性的导入自动装配呢?我们想想是不是要过滤一些,排除一些多余的呢?这个猜想不错,我们看看就明白究竟了。
//入参是注解属性元信息
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
//获取自动装配候选名单
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
//去除重复
configurations = this.removeDuplicates(configurations);
//去除自动装配排除的名单列表
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
//检查排除类名单是否合法
this.checkExcludedClasses(configurations, exclusions);
//从候选名单列表中移除需要排除的名单列表
configurations.removeAll(exclusions);
//过滤自动装配组件
configurations = this.filter(configurations, autoConfigurationMetadata);
//自动装配事件
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return StringUtils.toStringArray(configurations);
}
}
小伙伴儿们,又需要我们逐一层层深入了。记住,只有深入了,你才会体验到前所未有的爽,那感觉终生难忘,回味无穷,嘿嘿,,,,看源码是痛苦的,但看明白后就有种醍醐灌顶,豁然开朗的感觉。
2.2 获取候选装配组件
解读方法getCandidateConfigurations
从命名上可以知道Candidate是候选的意思,大概就是获取候选配置类信息
。
public class AutoConfigurationImportSelector{
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//加载在 `META-INF/spring.factories` 里的类名的数组,他们作为自动装配的候选类名单
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
}
}
}
我们继续跟进SpringFactoriesLoader.loadFactoryNames
这个方法看看
public final class SpringFactoriesLoader {
//配置文件路径
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
//此处又调用了该类的私有方法#loadSpringFactories()
return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
//小伙伴儿们我们继续深入....有多深都要进去,只是进去看看
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
//MultiValueMap就是个Map,因为返回就是Map
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
//加载指定路径下文件内容
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
//转为Resource
UrlResource resource = new UrlResource(url);
//加载为Peroperties文件进行读取
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Entry<?, ?> entry = (Entry)var6.next();
//我们打开META-INF/spring.factories文件看看,
//可以发现文件key是接口的全类名,value是实现类的全类名列表,代码自然就懂了
String factoryTypeName = ((String)entry.getKey()).trim();
String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11) {
String factoryImplementationName = var9[var11];
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}
}
说明:SpringFactoriesLoader
是Spring的工厂机制加载器,看完#loadSpringFactories方法,明白原理如下:
- 加载指定ClassLoader下META-INF/spring.factories文件资源内容
- 转为Properties文件进行读取,放入Map中,key为接口的全类名,value为实现类的全类名列表,然后进行返回。
找到maven依赖的自动装配模块org.springframework.boot:spring-boot-autoconfigure,META-INF/spring.factories文件下,以EnableAutoConfiguration
全类名为Key的配置如下所示:
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
//其他略.......
2.3 排除自动装配组件
接下来,执行this.getExclusions(annotationMetadata, attributes) 方法,去排除一些不需要的组件。
这样说你可能还不清楚,比如在@EnableAutoConfiguration
注解定义中可以看到
public @interface SpringBootApplication{
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
有两个属性分别是exclude
和excludeName
,在实际项目中你可能也这样写过,配置多数据源时,需要我们排除默认的数据源,使用我们自己配置的数据源,配置如下:
@SpringBootApplication(exclude={
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class})
这就是要告诉自动装配需要排除的组件类了。
protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
Set<String> excluded = new LinkedHashSet();
//@EnableAutoConfiguration注解中exclude和excludeName用来添加排除的组件
excluded.addAll(this.asList(attributes, "exclude"));
excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
excluded.addAll(this.getExcludeAutoConfigurationsProperty());
return excluded;
}
将需要排除的类放在集合中,然后返回,之后检查排除的集合类是否合法最后进行移除。
2.4 过滤自动装配组件
继续往下看了,调用configurations = this.filter(configurations, autoConfigurationMetadata); 方法进行过滤。
private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) {
long startTime = System.nanoTime();
String[] candidates = StringUtils.toStringArray(configurations);
boolean[] skip = new boolean[candidates.length];
boolean skipped = false;
//主要方法getAutoConfigurationImportFilters()
Iterator var8 = this.getAutoConfigurationImportFilters().iterator();
while(var8.hasNext()) {
//可以看出迭代的类是AutoConfigurationImportFilter的子类!!!!
AutoConfigurationImportFilter filter = (AutoConfigurationImportFilter)var8.next();
this.invokeAwareMethods(filter);
boolean[] match = filter.match(candidates, autoConfigurationMetadata);
//为节省篇幅,其他代码省略....
}
}
//#filter()方法调用
protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);
}
返回进入SpringFactoriesLoader
public static <T> List<T> loadFactories(Class<T> factoryClass, @Nullable ClassLoader classLoader) {
Assert.notNull(factoryClass, "'factoryClass' must not be null");
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
List<String> factoryNames = loadFactoryNames(factoryClass, classLoaderToUse);
return result;
}
可以看出AutoConfigurationImportSelector#filter中的AutoConfigurationImportFilter 对象集合是有SpringFactoriesLoader 加载的。找到maven依赖的自动装配模块org.springframework.boot:spring-boot-autoconfigure,META-INF/spring.factories文件下
# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnClassCondition
我们可以看到,SpringFactoriesLoader#loadFactories方法与我们前面看获取候选自动装配方法时调用的SpringFactoriesLoader#loadFactoryNames 差别是后者是静态方法,前者是调用后者的。点开OnClassCondition 可以发现它是AutoConfigurationImportFilter实现类。可以说明AutoConfigurationImportSelector#filter方法的作用是过滤META-INF/spring.factories 资源中那些当前ClassLoader不存在的类。
SpringBoot内部提供了特有的注解:条件注解(Conditional Annotation)。比如@ConditionalOnBean、@ConditionalOnClass、@ConditionalOnExpression、@ConditionalOnMissingBean等。@ConditionalOnClass用来判断需要依赖自动装配的class必需被ClassLoader提前装载,然后解析其注解元信息,从而跟据依赖是否存在来判断是否装载。
2.4 自动装配事件
private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {
List<AutoConfigurationImportListener> listeners = this.getAutoConfigurationImportListeners();
if (!listeners.isEmpty()) {
AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
Iterator var5 = listeners.iterator();
while(var5.hasNext()) {
AutoConfigurationImportListener listener = (AutoConfigurationImportListener)var5.next();
this.invokeAwareMethods(listener);
listener.onAutoConfigurationImportEvent(event);
}
}
}
AutoConfigurationImportListener用来监听AutoConfigurationImportEvent