• 第二章 SpringBoot核心运行原理


    2.1 核心运行原理

    springboot通过@EnableAutoConfiguration注解开启自动配置,加载spring.factories中注册的各种Autoconfiguration自动配置类,当某个AutoConfiguration类满足其注解@Conditional指定的生效条件时,则实例化该AutoConfiguration类中定义的Bean,并把这些Bean注册到Spring容器中,就可以完成依赖框架的自动配置。

    2.2 @EnableAutoConfiguration

    2.2.1 入口类和@SpringBootApplication

    入口类

    以下为springboot应用的常规入口类,形式上非常简单,类上面仅使用了@SpringBootApplication注解,在main方法中,指定入口类作为SpringApplication#run方法的运行参数,就可以启动springboot应用

    @SpringBootApplication
    public class TestApplication {
        public static void main(String[] args) {
            SpringApplication.run(TestApplication.class, args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    @SpringBootApplication

    该注解是springboot应用的核心注解,它里面组合了@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan

    @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 {
    
    	// @Alias注解:该注解用于桥接到其它注解,该注解的属性中制定了所桥接的注解类
    	@AliasFor(annotation = EnableAutoConfiguration.class)
    	Class<?>[] exclude() default {};  // 指定排除的自动配置类
    
    	@AliasFor(annotation = EnableAutoConfiguration.class)
    	String[] excludeName() default {};  // 指定排除的自动配置类类名
    	
    	@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
    	String[] scanBasePackages() default {}; // 指定扫描的基础包
    
    	@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
    	Class<?>[] scanBasePackageClasses() default {}; // 指定扫描的基础类
    
    	@AliasFor(annotation = Configuration.class)
    	boolean proxyBeanMethods() default true; // 是否生成配置类的代理类, 代理@Bean方法强制从spring容器中获取
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    我们刚学springboot的时候,就被“告知”:入口类所在的包及其子包中的组件将会被扫描。这也是要将入口类放在顶级package下的原因(如果放在比较低的层级,那么上级包的类或同级所在包的类无法扫描到),那么为什么呢?因为@SpringBootApplication注解上有个@ComponentScan注解,默认情况下,我们并没有指定任何扫描的基础包,而在ComponentScanAnnotationParser处理这个@ComponentScan注解的时候,获取到如果没有设置任何扫描的信息,那么就获取注解所标注的类所在的包作为扫描的基础包,因而基础包及其下面定义的组件都会被扫描到。我们可以,@SpringBootApplication(scanBasePackages = “com.zzhua.test”)桥接到@ComponentScan注解中的值,那么就只会com.将zzhua.test作为基础包扫描。

    2.2.2 @EnableAutoConfiguration注解解析

    @EnableAutoConfiguration

    该注解是由@SpringBootApplication注解组合而引入的,用于开启自动配置,它会根据类路径上是否有引入指定的包中的类,尝试猜测并配置项目中可能需要的bean。所以也可以使用该注解提供的exclude等方法,排除某些自动配置。

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage // 被该注解标记的类所在的包会作为自动配置基础包(比如扫描一些Entity啥的)
    @Import(AutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration {
    
    	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; // 是否开启自动配置(通过env设置)
    
    	Class<?>[] exclude() default {}; // 排除指定的类
    
    	String[] excludeName() default {}; // 排除指定名字的类
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2.3 AutoConfigurationImportSelector

    该类在@EnableAutoConfiguration注解中被@Import(AutoConfigurationImportSelector.class)组合而引入

    2.3.1 @Import

    该注解用于向spring容器中导入组件,在源码中很多@EnableXXX也是基于该注解实现的

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Import {
    
    	// 用来导入:
    	// 	1. @Configuration标注的类
    	//  2. 实现了ImportSelector或DeferedImportSelector接口的子类
    	//  3. 实现了ImportBeanDefinitionRegistrar接口的子类
    	//  4. 常规普通类(作为组件)
    	Class<?>[] value();
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2.3.2 ImportSelector&DeferedImportSelector接口

    public interface ImportSelector {
    
    	// 参数:包含了被@Import注解标注的类上的注解信息
    	// 返回值:返回的数组将都会作为spring容器的配置类,用于引入相关组件
    	String[] selectImports(AnnotationMetadata importingClassMetadata);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    如果ImportSelector的实现类,还实现了EnvironmentAware、BeanFactoryAware、BeanClassLoaderAware、ResourceLoaderAware接口,那么这些接口的回调都会在selectImports方法执行之前被回调,这样就可以拿到相应的对象了。

    区别

    @DeferedImportSelector会在所有的@Configuration类加载完成之后再加载返回的配置类,而ImportSelector在加载完@Configuration类之前先去加载返回的配置类,并且DeferedImportSelector的加载顺序可以通过@Order注解或实现Order接口来指定,并且它还可以了新的getImportGroup()来跨DeferedImportSelector实现自定义@Configuration的加载顺序。

    2.3.3 AutoConfigurationImportSelector功能概述

    @Override
    	public String[] selectImports(AnnotationMetadata annotationMetadata) {
    		// 获取env配置的spring.boot.enableautoconfiguration值,如果未配置,默认为true
    		if (!isEnabled(annotationMetadata)) {
    			return NO_IMPORTS; // 如果关闭默认配置,直接返回空数组,即所有自动配置类都不会自动配置了
    		}
    		// 加载类路径下META-INF/spring-autoconfigure-metadata.properties文件的所有数据
    		AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
    				.loadMetadata(this.beanClassLoader);
    				
    		// 【核心方法:获取所有的自动配置类】
    		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
    				annotationMetadata);
    				
    		// 返回所有自动配置类的数组
    		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    AutoConfigurationMetadataLoader#loadMetadata

    static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) {
    		try {
    			// 获取所有的文件
    			Enumeration<URL> urls = (classLoader != null) ? classLoader.getResources(path)
    					: ClassLoader.getSystemResources(path);
    			Properties properties = new Properties();
    			while (urls.hasMoreElements()) {
    				// 遍历文件,加载所有的属性
    				properties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource(urls.nextElement())));
    			}
    			return new PropertiesAutoConfigurationMetadata(properties);
    		}
    		catch (IOException ex) {
    			throw new IllegalArgumentException("Unable to load @ConditionalOnClass location [" + path + "]", ex);
    		}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    # 多个值,使用逗号分隔(分隔的作用在后面解析中处理)
    org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration.AutoConfigureAfter=org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration
    org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration.ConditionalOnClass=com.datastax.driver.core.Cluster,reactor.core.publisher.Flux,org.springframework.data.cassandra.core.ReactiveCassandraTemplate
    
    • 1
    • 2
    • 3

    加载元数据配置,通过加载类路径下,指定路径:META-INF/spring-autoconfigure-metadata.properties文件。加载此数据是为了后续过滤自动配置使用。SpringBoot使用一个Annotation的处理器来收集自动加载的条件,这些条件就可以配置在这个文件当中。Springboot会将收集好的自动配置类,根据此配置信息,使用加载的过滤器(默认配置了3种:OnBeanCondition、OnClassCondition、OnWebApplicationCondition,它们都继承了FilteringSpringBootCondition),再进行一次过滤(跟在自动配置类上添加这些@ConditionalOnClass作用是一样的)。目的就是为了减少@Configuratin类的数量,从而减少初始化bean的耗时。

    getAutoConfigurationEntry

    protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
    		AnnotationMetadata annotationMetadata) {
    	// 获取env中设置的spring.boot.enableautoconfiguration值, 是否开启默认自动配置
    	if (!isEnabled(annotationMetadata)) {
    		return EMPTY_ENTRY;
    	}
    	
    	// 获取到@Import注解所标注的类上的所有注解,中的@EnableAutoConfiguratin注解的信息
    	// AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(EnableAutoConfiguration.class.getName(), true))
    	AnnotationAttributes attributes = getAttributes(annotationMetadata);
    	
    	// 使用SpringFactoriesLoader加载META-INFO/spring.factories文件中的@EnableAutoConfiguratin注解所对应的值(即自动配置类)
    	// 具体的加载细节:https://www.processon.com/view/link/61f0c54ee0b34d616d516e16
    	List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    
    	// 使用LinkedHashset来对所有的自动配置类来个去重操作
    	configurations = removeDuplicates(configurations);
    
    	// 根据@EanbleAutoConfiguratin注解的exclude和excludeName以及env里的spring.autoconfigure.exclude来获取需要排除的自动配置类
    	// (初步过滤)
    	Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    
    	// 你如果要排除某个自动配置类, 但是这个自动配置类又没有被加载到, 就会抛异常
    	checkExcludedClasses(configurations, exclusions);
    
    	// 移除 要排除 的自动配置类
    	configurations.removeAll(exclusions);
    
    	// 检查配置类的注解是否符合spring.factories文件中AutoConfigurationImportFilter指定的注解检查条件, 如果不满足将会被移除掉
    	// (再次过滤)
    	configurations = filter(configurations, autoConfigurationMetadata);
    
    	// 获取到spring.factories文件中所配置的AutoConfigurationImportListener监听器, 组装AutoConfigurationImportEvent, 
    	// 并回调监听器的onAutoConfigurationImportEvent方法以广播事件
    	fireAutoConfigurationImportEvents(configurations, exclusions);
    
    	// 简单封装
    	return new AutoConfigurationEntry(configurations, exclusions);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    isEnabled(AnnotationMetadata metadata)
    protected boolean isEnabled(AnnotationMetadata metadata) {
    	// 如果是 AutoConfigurationImportSelector类
    	if (getClass() == AutoConfigurationImportSelector.class) {
    		// 固定的值"spring.boot.enableautoconfiguration"
    		return getEnvironment().getProperty(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true);
    	}
    	// 非AutoConfigurationImportSelector类,全都返回true
    	return true;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    getAttributes(AnnotationMetadata metadata)
    protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
    
    	// 找的注解就是 @EnableAutoConfiguration
    	String name = getAnnotationClass().getName();
    
    	// 提取@EnableAutoConfiguration注解的属性值, 封装到AnnotationAttributes(继承自LinkedHashMap)
    	AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));
    	
    	Assert.notNull(attributes, () -> "No auto-configuration attributes found. Is " + metadata.getClassName()
    			+ " annotated with " + ClassUtils.getShortName(name) + "?");
    	return attributes;
    }
    
    protected Class<?> getAnnotationClass() {
    	// 找的注解就是 EnableAutoConfiguration
    	return EnableAutoConfiguration.class;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes)
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    
    	// 使用SpringFactoriesLoader加载META-INF/spring.factories中@EnableAutoConfiguration注解全类名对应的值
    	// 具体的加载细节:https://www.processon.com/view/link/61f0c54ee0b34d616d516e16
    	List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),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;
    }
    
    protected Class<?> getSpringFactoriesLoaderFactoryClass() {
    	// 找的注解就是 @EnableAutoConfiguration
    	return EnableAutoConfiguration.class;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    removeDuplicates(List list)
    protected final <T> List<T> removeDuplicates(List<T> list) {
    	// 仅仅用LinkedHashSet去重
    	return new ArrayList<>(new LinkedHashSet<>(list));
    }
    
    • 1
    • 2
    • 3
    • 4
    getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes)
    protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    	Set<String> excluded = new LinkedHashSet<>();
    
    	// 那其实我们使用@SpringBootApplication注解, 并没有碰触到@EnableAutoConfiguration呀
    	// 那是怎么修改到exclude和excludeName的属性值呢?
    	// 前面提到了@SpringBootApplication注解的这两个属性使用了@AliasFor将属性桥接到@EnableAutoConfiguration了
    
    	// 获取@EnableAutoConfiguration注解的exclude属性
    	excluded.addAll(asList(attributes, "exclude"));
    
    	// 获取@EnableAutoConfiguration注解的excludeName属性
    	excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
    
    	// 从env中获取spring.autoconfigure.exclude对应要排除的自动配置类
    	excluded.addAll(getExcludeAutoConfigurationsProperty());
    	return excluded;
    }
    
    private List<String> getExcludeAutoConfigurationsProperty() {
    	if (getEnvironment() instanceof ConfigurableEnvironment) {
    
    		// 绑定器, 拿到env中的propertySource
    		// PropertyPlaceholderHelper用来解析"${x:y}"占位符
    		// ApplicationConversionService(ConversionService的实现)用来类型转换
    		Binder binder = Binder.get(getEnvironment());
    		
    		// 获取固定的值:spring.autoconfigure.exclude
    		return binder.bind(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class).map(Arrays::asList)
    				.orElse(Collections.emptyList());
    	}
    	String[] excludes = getEnvironment().getProperty(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class);
    	return (excludes != null) ? Arrays.asList(excludes) : Collections.emptyList();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    checkExcludedClasses(List configurations, Set exclusions)
    private void checkExcludedClasses(List<String> configurations, Set<String> exclusions) {
    	List<String> invalidExcludes = new ArrayList<>(exclusions.size());
    	
    	// 遍历要排除的自动配置类
    	for (String exclusion : exclusions) {
    		// 如果这个类存在, 但是根本就不在自动配置类集合中,就会收集异常
    		if (ClassUtils.isPresent(exclusion, getClass().getClassLoader()) && !configurations.contains(exclusion)) {
    			invalidExcludes.add(exclusion);
    		}
    	}
    
    	// 将收集的异常抛出去
    	if (!invalidExcludes.isEmpty()) {
    		handleInvalidExcludes(invalidExcludes);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    filter(List configurations, AutoConfigurationMetadata 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使用SpringFactoriesLoader
    	// 加载spring.factories中AutoConfigurationImportFilter全类名所对应的过滤器,并实例化
    	// autoconfigure包中默认提供了3个filter,默认是OnBeanCondition、OnClassCondition、OnWebApplicationCondition
    	// 它们都继承自FilteringSpringBootCondition抽象类(可以认为这个抽象类的实现就是用来过滤springboot的自动配置类的)
    	for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) { // 遍历过滤器
    	
    		// 回调Aware接口, 设置BeanClassLoader、BeanFactory、Environment、ResourceLoader
    		invokeAwareMethods(filter);
    
    		// 使用过滤器对每个候选的自动配置类, 使用boolean数组记录是否匹配
    		boolean[] match = filter.match(candidates, autoConfigurationMetadata);
    		for (int i = 0; i < match.length; i++) {
    			if (!match[i]) { // 如果有不匹配的
    				skip[i] = true;         // 标记要跳过此候选的自动配置类
    				candidates[i] = null;   // 候选的自动配置类置为null
    				skipped = true;         // 标记有要跳过的自动配置类
    			}
    		}
    	}
    	
    	// 如果没有要跳过的自动配置类, 就返回全部的自动配置类
    	if (!skipped) {
    		return configurations;
    	}
    
    	// 最终要返回的 自动配置类 集合
    	List<String> result = new ArrayList<>(candidates.length);
    	for (int i = 0; i < candidates.length; i++) {
    		if (!skip[i]) { // 忽略要跳过的自动配置类
    			result.add(candidates[i]);
    		}
    	}
    	if (logger.isTraceEnabled()) {
    		int numberFiltered = configurations.size() - result.size();
    		logger.trace("Filtered " + numberFiltered + " auto configuration class in "
    				+ TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");
    	}
    	return new ArrayList<>(result);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    FilteringSpringBootCondition
    @Override
    public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {
    
    	// 只是做一个报告, 无关紧要
    	ConditionEvaluationReport report = ConditionEvaluationReport.find(this.beanFactory);
    	
    	// 抽象模板方法, 交给具体子类实现, 这里以OnClassCondition为例继续看看
    	ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses, autoConfigurationMetadata);
    	
    	// 与自动配置类等长的boolean数组
    	boolean[] match = new boolean[outcomes.length];
    	
    	// 只是做一个报告, 无关紧要
    	for (int i = 0; i < outcomes.length; i++) {
    		match[i] = (outcomes[i] == null || outcomes[i].isMatch());
    		if (!match[i] && outcomes[i] != null) {
    			logOutcome(autoConfigurationClasses[i], outcomes[i]);
    			if (report != null) {
    				report.recordConditionEvaluation(autoConfigurationClasses[i], this, outcomes[i]);
    			}
    		}
    	}
    	
    	return match;
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    OnClassCondition
    @Order(Ordered.HIGHEST_PRECEDENCE)
    class OnClassCondition extends FilteringSpringBootCondition {
    
    	@Override
    	protected final ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
    			AutoConfigurationMetadata autoConfigurationMetadata) {
    		// Split the work and perform half in a background thread if more than one
    		// processor is available. Using a single additional thread seems to offer the
    		// best performance. More threads make things worse.
    		if (Runtime.getRuntime().availableProcessors() > 1) {
    			return resolveOutcomesThreaded(autoConfigurationClasses, autoConfigurationMetadata);
    		}
    		else {
    			// 假设处理器只有一个, 走这边
    			// 自动配置类 和 由 spring-autoconfigure-metadata.properties文件加载的属性值AutoConfigurationMetadata 
    			// 封装到了内部类的OutcomesResolver 解析器
    			OutcomesResolver outcomesResolver = new StandardOutcomesResolver(autoConfigurationClasses, 0,
    					autoConfigurationClasses.length, autoConfigurationMetadata, getBeanClassLoader());
    			// 那剩下就要看这个解析器的resolveOutcomes方法了
    			return outcomesResolver.resolveOutcomes();
    		}
    	}
    }
    
    
    private ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses, int start, int end,
    		AutoConfigurationMetadata autoConfigurationMetadata) {
    	
    	ConditionOutcome[] outcomes = new ConditionOutcome[end - start];
    	
    	for (int i = start; i < end; i++) {
    	
    		// 遍历每个自动配置类
    		String autoConfigurationClass = autoConfigurationClasses[i];
    		
    		// 忽略null
    		if (autoConfigurationClass != null) {
    			// 固定格式是: 自动配置类全类名.ConditionalOnClass
    			// 以上面的值, 到pring-autoconfigure-metadata.properties文件中找配置的值
    			// 比如说:org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration.ConditionalOnClass=com.rabbitmq.client.Channel,\
    			//               org.springframework.amqp.rabbit.core.RabbitTemplate
    			String candidates = autoConfigurationMetadata.get(autoConfigurationClass, "ConditionalOnClass");
    
    			// 如果有配置这个值的话
    			// (所以如果要给自动配置类生效添加条件, 我们也可以往这个文件中写入对应的要求, 也可以自定义AutoConfigurationImportFilter的实现)
    			if (candidates != null) {
    			
    				// 把配置的值传进去, 做条件判断
    				outcomes[i - start] = getOutcome(candidates);
    			}
    		}
    	}
    	return outcomes;
    }
    
    private ConditionOutcome getOutcome(String candidates) {
    	try {
    		// 语法是使用逗号隔开多个值, 如果没有逗号, 只需要判断一个就行了
    		if (!candidates.contains(",")) {
    			return getOutcome(candidates, this.beanClassLoader);
    		}
    		// 如果有逗号, 以逗号分隔, 挨个判断, 第一个不为null就表示已经有结果了, 立即返回
    		for (String candidate : StringUtils.commaDelimitedListToStringArray(candidates)) {
    			ConditionOutcome outcome = getOutcome(candidate, this.beanClassLoader);
    			if (outcome != null) {
    				return outcome;
    			}
    		}
    	}
    	catch (Exception ex) {
    		// We'll get another chance later
    	}
    	return null;
    }
    
    private ConditionOutcome getOutcome(String className, ClassLoader classLoader) {
    	// 不存在className的类, 就返回true
    	if (ClassNameFilter.MISSING.matches(className, classLoader)) {
    		// 因为条件是onClassCondition, 所以这里是不匹配的
    		return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnClass.class)
    				.didNotFind("required class").items(Style.QUOTE, className));
    	}
    	// null表示接着判断下一个
    	return null;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    fireAutoConfigurationImportEvents(List configurations, Set exclusions)
    private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {
    
    	// SpringFactoriesLoader加载AutoConfigurationImportListener全类名对应的所有实例
    	List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();
    
    	// 如果AutoConfigurationImportListener集合不为空
    	if (!listeners.isEmpty()) {
    	
    		// 封装事件对象
    		AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
    
    		// 遍历所有的监听器
    		for (AutoConfigurationImportListener listener : listeners) {
    		
    			// 回调Aware接口, 设置BeanClassLoader、BeanFactory、Environment、ResourceLoader
    			invokeAwareMethods(listener);
    	
    			// 通知每个监听器
    			listener.onAutoConfigurationImportEvent(event);
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    2.4 @Conditional注解

    2.4.1 @Conditional

    spring4.0中定义的注解

    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Conditional {
    
    	// 所有的Condition都满足时, 对应标注的组件才会生效
    	Class<? extends Condition>[] value();
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    Condition接口

    @FunctionalInterface
    public interface Condition {
    
    	// 传入的2个参数, 作为条件判断的基础依据
    	boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    ConditionContext

    public interface ConditionContext {
    
    	// bean注册中心, 可以获取容器中是否定义了相关的bean
    	BeanDefinitionRegistry getRegistry();
    
        // bean工厂, 可以获取容器中存在的bean
    	@Nullable
    	ConfigurableListableBeanFactory getBeanFactory();
    
    	// env环境配置, 可以获取配置信息
    	Environment getEnvironment();
    	
    	// 资源加载器
    	ResourceLoader getResourceLoader();
    
    	// 类加载器
    	@Nullable
    	ClassLoader getClassLoader();
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    AnnotatedTypeMetadata

    可以获取所标注的 或者 方法 上的所有注解信息,而无须加载对应的类(asm实现)

    public interface AnnotatedTypeMetadata {
    
    	// 获取所有的注解
    	MergedAnnotations getAnnotations();
    
    	// 是否标注了指定注解名称的注解
    	boolean isAnnotated(String annotationName);
    	
    	// 获取指定注解的所有数据
    	Map<String, Object> getAnnotationAttributes(String annotationName);
    	
    	Map<String, Object> getAnnotationAttributes(String annotationName,
    	                                            boolean classValuesAsString);
    	
    	MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    例如:

    @Component("s1")
    @Service("s2")
    public class Student {
    
        static {
            System.out.println("static executing...");
        }
    
        public Student() {
            System.out.println("student cons...");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    
    public class TestApp {
    
        public static void main(String[] args) throws IOException {
    
            SimpleMetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
            MetadataReader stuMetadataReader = metadataReaderFactory.getMetadataReader("com.zzhua.test.Student");
            boolean annotated = stuMetadataReader.getAnnotationMetadata().isAnnotated(Component.class.getName());
            System.out.println(annotated);
    
    		Map<String, Object> annotationAttributes = stuMetadataReader.getAnnotationMetadata().getAnnotationAttributes(Component.class.getName());
            System.out.println(annotationAttributes); // {value=s1}
    
            MultiValueMap<String, Object> allAnnotationAttributes = stuMetadataReader.getAnnotationMetadata().getAllAnnotationAttributes(Component.class.getName());
            System.out.println(allAnnotationAttributes); // {value=[s1, ]}
        }
    	// 结果只输出了 true, 静态代码块并未执行, 说明这种方式下, 
    	// spring是没有加载这个类的, 但是可以获取到类上面是否包含指定的注解
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    2.4.2 @Conditional衍生注解

    由@Conditional注解衍生而来的注解,这些注解上都标注了@Conditinal注解,并且指定了Condition接口的实现类,当满足指定的条件时,被该注解标注的类才会生效。

    @ConditionalOnBean               当容器中由指定bean时
    @ConditionalOnMissingBean        当在容器中没有指定bean时
    @ConditionalOnClass              当在类路径下有指定类时
    @ConditionalOnMissingClass       当在类路径下没有有指定类时
    @ConditionalOnProperty           当指定的属性有指定的值时
    @ConditionalOnExpression         当spel表达式为true时
    @ConditionalOnWebApplication     当在web容器时
    ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    以@ConditionalOnMissingBean 为例

    @Target({ ElementType.TYPE, ElementType.METHOD })
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Conditional(OnBeanCondition.class) // 注意这里有个@Conditional注解, 并且有OnBeanCondition条件要满足
    public @interface ConditionalOnMissingBean {
    
    	Class<?>[] value() default {};
    
    	String[] type() default {};
    
    	Class<?>[] ignored() default {};
    
    	String[] ignoredType() default {};
    	
    	Class<? extends Annotation>[] annotation() default {};
    
    	String[] name() default {};
    
    	SearchStrategy search() default SearchStrategy.ALL;
    
    	Class<?>[] parameterizedContainer() default {};
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    OnBeanCondition
    @Order(Ordered.LOWEST_PRECEDENCE)
    class OnBeanCondition extends FilteringSpringBootCondition implements ConfigurationCondition {
    	
    	@Override
    	public ConfigurationPhase getConfigurationPhase() {
    		return ConfigurationPhase.REGISTER_BEAN;
    	}
    
    	// 此方法用于重写FilteringSpringBootCondition抽象类中的方法
    	// 		根据spring-autoconfigure-metadata.properties文件对自动配置类再次筛选
    	@Override
    	protected final ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
    			                                       AutoConfigurationMetadata autoConfigurationMetadata) {
    		// 
    	}
    
    	// 该类同时处理: @ConditionalOnBean、
    	//             @ConditionalOnSingleCandidate、
    	//             @ConditionalOnMissingBean
    	//            这3个注解
    	@Override
    	public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
    	
    		ConditionMessage matchMessage = ConditionMessage.empty();
    		
    		MergedAnnotations annotations = metadata.getAnnotations();
    		
    		if (annotations.isPresent(ConditionalOnBean.class)) {
    			// ... 对@ConditionalOnBean注解的处理
    		}
    		
    		if (metadata.isAnnotated(ConditionalOnSingleCandidate.class.getName())) {
    			// ... 对@ConditionalOnSingleCandidate注解的处理
    		}
    
    		// 如果 方法或类 上有@ConditionalOnMissingBean注解
    		if (metadata.isAnnotated(ConditionalOnMissingBean.class.getName())) {
    			// 封装到Spec中
    			Spec<ConditionalOnMissingBean> spec = new Spec<>(context, metadata, annotations,
    					ConditionalOnMissingBean.class);
    			
    			// 从容器中根据@ConditionalOnMissingBean注解中的条件匹配
    			MatchResult matchResult = getMatchingBeans(context, spec);
    			
    			// 如果根据条件找到了满足条件的bean, 那就是不匹配
    			if (matchResult.isAnyMatched()) {
    				String reason = createOnMissingBeanNoMatchReason(matchResult);
    				// 返回条件不满足
    				return ConditionOutcome.noMatch(spec.message().because(reason));
    			}
    
    			// 没有找到满足条件的bean信息
    			matchMessage = spec.message(matchMessage).didNotFind("any beans").atAll();
    		}
    		// 匹配
    		return ConditionOutcome.match(matchMessage);
    	}
    
    	// 省略...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
  • 相关阅读:
    静态和默认路由配置-----计算机网络
    JDK17 New Feature
    山西电力市场日前价格预测【2023-10-22】
    y88.第五章 分布式链路追踪系统 -- 分布式链路追踪系统简介和部署skywalking(二)
    排序-基数排序
    读写算杂志社读写算编辑部读写算杂志2022年第30期目录
    [附源码]Python计算机毕业设计Django保护濒危动物公益网站
    Python进阶复习-文件与异常
    如何使用PHP替换回车为br
    C语言 深入探究C语言中的文件操作
  • 原文地址:https://blog.csdn.net/qq_16992475/article/details/126793581