上篇文章中, 《springboot源码(一)启动流程+自动配置原理分析》,简单分析了启动流程,其中涉及到了@SpringBootApplication注解,本文针对其中的exclude属性的作用及其原理,进行分析。
一.使用姿势
比如我的工程里引入的elasticsearch的依赖,使用了es的功能,但是有时我的es环境没准备好,但是我想启用项目,这时就会报错,那么我就可以将es相关的配置exclude掉,这个springboot在启动的时候就不去连接配置es了。
活着排除DataSourceAutoConfiguration,因为这个是自动配置单数据源的,如果你想配置多数据源,那么就需要把这个排除掉,然后自己单独配置多数据源。
exclude参数使用:
@SpringBootApplication
(exclude = {DataSourceAutoConfiguration.class, ElasticsearchDataAutoConfiguration.class,DataSourceAutoConfiguration.class})
public class Demo1Application {
@SpringBootApplication注解排除参数,不光支持exclude,还有一个excludeName,源码如下:
public @interface SpringBootApplication {
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
@AliasFor(annotation = EnableAutoConfiguration.class)
Class<?>[] exclude() default {};
/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
@AliasFor(annotation = EnableAutoConfiguration.class)
String[] excludeName() default {};
excludeName参数使用:
@SpringBootApplication(excludeName = {"org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration",
"org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration"})
也可以exclude和excludeName同时混合使用。
二.运行原理
首先,@SpringBootApplication注解继承了@EnableAutoConfiguration,同时exclude和excludeName参数使用了@AliasFor修饰,意味着我们给@SpringBootApplication指定exclude属性值的时候,相当于给@EnableAutoConfiguration的exclude参数也指定了相同的值。
springboot的自动配置注解,@EnableAutoConfiguration注解中Import了AutoConfigurationImportSelector.class,其中的如下方法中:
protected AutoConfigurationEntry getAutoConfigurationEntry(
AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
//获取注解中的所有属性,也就是exclude和excludeName
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//获取spring-boot-autoconfigure包中,spring.factories中的配置类
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
//去除重复的配置类
configurations = removeDuplicates(configurations);
//去除已经排除掉的
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
//校验是否是有效排除
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
//去除不符合condition条件的
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
说明:
1.getCandidateConfigurations(annotationMetadata,attributes); 获取到了spring-boot-autoconfigure包中,spring.factories中,key为spring-boot-autoconfigure包中,spring.factories中的配置类的配置类,总共118个;
2.getExclusions(annotationMetadata, attributes);获取已经被排除的类;
3.removeAll(exclusions); 从集合中排除exclusions
打开方法看下:
protected Set<String> getExclusions(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
Set<String> excluded = new LinkedHashSet<>();
excluded.addAll(asList(attributes, "exclude"));
excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
excluded.addAll(getExcludeAutoConfigurationsProperty());
return excluded;
}
很简单,就是把exclude的值和excludeName的值拿出来放到set集合中返回。
总结,springboot会扫描spring.factories配置文件中的配置类,保存到集合,然后在扫描exclude和excludeName中配置的类,将其总集合中排除即可。