Spring Boot 的自动配置原理

 2022-08-25
原文地址:https://cloud.tencent.com/developer/article/2022600

前言

springboot的出现大大简化了开发的过程,让开发任能够更加专注于业务的开发,对于其自动配置的原理有必要进行一个梳理学习

    @SpringBootApplication
    public class MeasApplication  {
    	public static void main(String[] args) {
    		SpringApplication.run(MeasApplication.class, args);
    
    	}
    
    
    }

首先看下程序的main方法入口处加了一个SpringBootApplication注解,进入注解

    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
    		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
    public @interface SpringBootApplication {
    }

进入之后可以看到这里有个@EnableAutoConfiguration表示启用自动配置进入这个注解可以看到

    @AutoConfigurationPackage
    @Import(AutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration {
    }

这里面有2个重要的注解:

  • @AutoConfigurationPackage,利用Registrar往容器中批量导入组件

看看是怎么做的

    @Import(AutoConfigurationPackages.Registrar.class)
    public @interface AutoConfigurationPackage {
    }

202208252253276301.png

这里的metadata指的是标有@AutoConfigurationPackages注解的类,获取该类所在的包,然后将该包下所有的组件扫描到spring容器中(这也就解释了为什么默认路径是主程序main所在的包)

@AutoConfigurationPackage注解的主要作用就是将主程序类所在包及所有子包下的组件到扫描到spring容器中

202208252253297572.png

接下来看第二个注解:@Import(AutoConfigurationImportSelector.class) 导入一个AutoConfigurationImportSelector组件,在这个类中获取了所有的配置,转化成String类型的数组,核心是利getAutoConfigurationEntry方法往容器中导入组件

202208252253316283.png

如下图所示,通过getCandidateConfigurations方法获取所有的候选配置,得到这132个组件将其导入到容器中

202208252253334324.png

接下来来看看getCandidateConfigurations这个方法是从哪里获取到的这些候选配置

     protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
            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;
        }

进入loadFactoryNames方法点击loadSpringFactories方法

202208252253356885.png

这里可以看到是从所有的spring的依赖jar包的中META-INF/spring.factories这个这个路径下来找

202208252253374636.png

202208252253393117.png

这里的核心是从spring-boot-autoconfigure-2.4.1.jar的META-INF/spring.factories这个路径下来找,这个文件中写死了springboot一启动就要给容器中添加所有的配置类

202208252253412508.png

虽然启动时默认加载所有的配置类,但是最终还是按需来开启,可以通过@ConditionalOnClass注解来进行表示,例如:

说明只有类路径下有Advice这个类,AspectJAutoProxyingConfiguration这个类才能生效

202208252253433379.png

2022082522534543010.png

以AopAutoConfiguration这个为例来进行深入学习: 1 首先可以看到在spring.factories已经配置了AopAutoConfiguration

2022082522534751411.png

2 进入AopAutoConfiguration

2022082522534955512.png

扩展

ConditionalOnMissingClass注解表示在没有Advice这个类的情况下生效

@ConditionalOnMissingClass({"org.aspectj.weaver.Advice"})

2022082522535152013.png

WebMvcProperties.class表示这个类和配置文件绑定,用于封装配置文件中的数据

2022082522535373714.png

springboot启动时获取容器中有的组件名:

    public static void main(String[] args) {
    		ConfigurableApplicationContext run = SpringApplication.run(MeasApplication.class, args);
    		String[] string = run.getBeanDefinitionNames();
    		for(String str: string){
    			System.out.println(str);
    		}
    		int count = run.getBeanDefinitionCount();
    		System.out.println("个数为:"+count);
    	}

2022082522535549615.png