上篇文章中, 《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中配置的类,将其总集合中排除即可。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐