一起来了解SpringBoot的配置原理(SpringBoot配置原理详解)

我们从SpringBoot的主程序类来看

  1. 首先主程序类上有@SpringBootApplication注解,点进去一看,知道它又等价于以下以下三个注解
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication{}
    
  1. 接下来就开始从这三个注解一个个出发,首先第一个是@SpringBOotConfiguration
    @SpringBootConfiguration注解点进去可看见 @Configuration,所以代表当前是一个配置类
  2. 然后看@ComponentScan,这个注解很明显就是包扫描,扫描注解并实例化且放入容器中
  3. 最后就把重点放到@EnableAutoConfiguration上了,一起来吧!
    它主要为:
    @AutoConfigurationPackage
    @Import(AutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration {}
    (1)@AutoConfigurationPackage
    自动配置包?指定了默认的包规则
@Import(AutoConfigurationPackages.Registrar.class)  //给容器中导入一个组件
public @interface AutoConfigurationPackage {}

//利用Registrar给容器中导入一系列组件
//将指定的一个包下的所有组件导入进来?MainApplication 所在包下。

以上Registrar类

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
        Registrar() {
        }

		//该方法时利用利用Registrar批量给容器中导入一系列组件
        public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
            AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));Enable
        }

        public Set<Object> determineImports(AnnotationMetadata metadata) {
            return Collections.singleton(new AutoConfigurationPackages.PackageImports(metadata));
        }
}

在registerBeanDefinitions这个方法中,可以得到:

  • 参数metadata是一注解源信息,其实是在主程序类上面的,因为我们是从@EnableAutoConfiguration出发的,并且,该注解在主程序类上,信息如下:在这里插入图片描述
  • 接下来看该方法内容
    计算(new AutoConfigurationPackages.PackageImports(metadata).getPackageNames())可以得到包名:在这里插入图片描述
    这也就是为什么没有在主程序类配置包扫描路径,默认路径为主程序类所在包之下了
    总的来说,Register类的作用就是 将指定的一个包下的所有组件导入进来,也就是@AutoConfigurationPackage注解的作用
    **(2)**接下来看@Import({AutoConfigurationImportSelector.class})
    点进去看到往下翻找到该方法
public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }

这个方法里面我们需要主要研究getAutoConfigurationEntry这个方法:

protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            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.getConfigurationClassFilter().filter(configurations);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }

其中

List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);

该方法的作用: 获取到所有需要导入到容器中的配置类
深入该方法:

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;
}

其中

List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());

从kiadFactoryNames方法出发,深入方法之后得到:

 Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader)

作用为:利用工厂加载,得到所有的组件
那么得到所有的组件,从哪来呢?
在 SpringFactoriesLoader类中可以看到此行代码

public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

和此方法
Map<String, List> loadSpringFactories(@Nullable ClassLoader classLoader)
该方法在加载资源时候,就是用到上方属性FACTORIES_RESOURCE_LOCATION,所以路径就被指定到"META-INF/spring.factories"。举例如下:在这里插入图片描述
点开spring.factories:

# Application Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.devtools.restart.RestartScopeInitializer

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.devtools.restart.RestartApplicationListener,\
org.springframework.boot.devtools.logger.DevToolsLogFactory.Listener

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.devtools.autoconfigure.DevToolsDataSourceAutoConfiguration,\
org.springframework.boot.devtools.autoconfigure.DevToolsR2dbcAutoConfiguration,\
org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration,\
org.springframework.boot.devtools.autoconfigure.RemoteDevToolsAutoConfiguration

# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.devtools.env.DevToolsHomePropertiesPostProcessor,\
org.springframework.boot.devtools.env.DevToolsPropertyDefaultsPostProcessor

其中的Auto Configure就是该starter(场景)下,需要加载且自动导入的相关类
所以,资源加载过后,然后再实例化并放入容器中,最终实现了自动配置
第二个类讲解的总结,捋顺下思路

1、利用getAutoConfigurationEntry(annotationMetadata);给容器中批量导入一些组件
2、调用List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes)获取到所有需要导入到容器中的配置类
3、利用工厂加载 Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader);得到所有的组件
4、从META-INF/spring.factories位置来加载一个文件。
	默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
    spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories
    

至此,自动配置的基本实现思路已经结束。

但是,以下需要注意

  1. 扫描spring.factories资源后,所有配置类都会被加载不错,但是起作用的可不一定是全部,一些配置类中的注解是需要一定条件下才会生效,一些对象才会被实例化放入容器等操作才会生效。如图:
    在这里插入图片描述
    条件注解:@ConditionOnProperty,若不满足该条件此类中所有注解不会生效

  2. SpringBoot默认会在底层配好所有的组件。但是如果用户自己配置了以用户的优先
    举例:在这里插入图片描述
    关键注解:@ConditionalOnMissingClass

SpringBoot自动配置原理总结如下:

  • SpringBoot先加载所有的自动配置类 xxxxxAutoConfiguration
  • 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。xxxxProperties里面拿。xxxProperties和配置文件进行了绑定
  • 生效的配置类就会给容器中装配很多组件
  • 只要容器中有这些组件,相当于这些功能就有了
  • 定制化配置
    ○ 直接用@Bean替换底层的组件
    ○ 去看这个组件是获取的配置文件什么值就去修改,只需要修改对应名字的值就行

以上是关于SpringBoot的自动配置原理,对于这篇文章的内容到此结束,感谢观看~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值