SpringBoot自动配置原理

SpringBoot自动配置原理

什么是自动配置?

在学习SSM开发项目时,我们需要自己引入spring、springMVC以及mybatis的依赖,并且需要使用配置文件或者java config来进行配置,比如配置视图解析器等等组件。但springboot 为我们提供了一种便利的开发方式:自动配置,我们只需要引入特定的starter即可,其它需要的组件springboot会自动帮我们加入到容器中,这就是自动配置。

SpringBoot是怎么实现自动配置的?

本文基于SpringBoot2.1.4书写。

查看主启动类,我们发现类上有一个@SpringBootApplication注解,这个注解就是SpringBoot实现自动配置的关键。

@SpringBootApplication
public class OrderApplication {

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

继续深入下去,我们进入@SpringBootApplication注解的源码,发现该注解上方有如下注解:

@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) })

其中:

  • @SpringBootConfiguration是SpringBoot项目的配置注解,也是一个组合注解,在SpringBoot项目中推荐使用@SpringBootConfiguration替代@Configuration
  • @ComponentScan的作用就是根据定义的扫描路径,把符合扫描规则的类装配到spring容器中;
  • @EnableAutoConfiguration就是告诉SpringBoot开启自动配置功能,自动配置的重点就在这个注解中。

我们认清了自动配置的重点——@EnableAutoConfiguration,接下来就去研究这个注解。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

同样,我们逐个逐个开始进行分析。

@AutoConfigurationPackage

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {

}

我们查看了@AutoConfigurationPackage注解,发现他导入了AutoConfigurationPackages下的Registrar

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

   @Override
   public void registerBeanDefinitions(AnnotationMetadata metadata,
         BeanDefinitionRegistry registry) {
      register(registry, new PackageImport(metadata).getPackageName());
   }

   @Override
   public Set<Object> determineImports(AnnotationMetadata metadata) {
      return Collections.singleton(new PackageImport(metadata));
   }

}

我们发现这个Registrar类中有一个registerBeanDefinitions方法,该方法的主要作用就是将主程序类所在包及其所有子包下的组件扫描到Spring容器中。

@Import(AutoConfigurationImportSelector.class)

**该注解是重点之中的重点。**该注解给当前配置类导入自动配置类AutoConfigurationImportSelector

该类中有个selectImports方法,该方法的起到的作用是,根据配置文件(spring.factories),将需要注入到容器的bean注入到容器。(该方法在SpringBoot启动时不会被调用!!!)

@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
   if (!isEnabled(annotationMetadata)) {
      return NO_IMPORTS;
   }
   AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
         .loadMetadata(this.beanClassLoader);
   AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(
         autoConfigurationMetadata, annotationMetadata);
   return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

该方法中有两个主要用到的方法:

  • 一个是AutoConfigurationMetadataLoader.loadMetadata,该方法会默认加载类路径下 META-INF/spring-autoconfigure-metadata.properties内的配置;
  • 另外一个是getAutoConfigurationEntry

getAutoConfigurationEntry方法是SpringBoot启动时调用的方法,而不是selectImports方法。

该方法主要功能是加载类路径下META-INF/spring.factories,如果@EnableAutoConfiguration注解传入了exclude参数,就把exclude对应的类从META-INF/spring.factories中移除,并把不满足META-INF/spring-autoconfigure-metadata.properties中所写条件的那些配置类过滤掉,返回经过筛选后的所有配置类。

protected AutoConfigurationEntry getAutoConfigurationEntry(
      AutoConfigurationMetadata autoConfigurationMetadata,
      AnnotationMetadata annotationMetadata) {
   // 检查自动装配开关
   if (!isEnabled(annotationMetadata)) {
      return EMPTY_ENTRY;
   }
   // 获取EnableAutoConfiguration中的参数,exclude()/excludeName()
   AnnotationAttributes attributes = getAttributes(annotationMetadata);
   // 获取需要自动装配的所有配置类,读取META-INF/spring.factories 
   List<String> configurations = getCandidateConfigurations(annotationMetadata,
         attributes);
   // 去重,List转Set再转List
   configurations = removeDuplicates(configurations);
   // 从EnableAutoConfiguration的exclude/excludeName属性中获取排除项
   Set<String> exclusions = getExclusions(annotationMetadata, attributes);
   // 检查需要排除的类是否在configurations中,不在报错
   checkExcludedClasses(configurations, exclusions);
   // 从configurations去除exclusions
   configurations.removeAll(exclusions);
   // 对configurations进行过滤,剔除掉不满足 spring-autoconfigure-metadata.properties 所写条件的配置类   
   configurations = filter(configurations, autoConfigurationMetadata);
   // 监听器 import 事件回调
   fireAutoConfigurationImportEvents(configurations, exclusions);
   // 返回(configurations, exclusions)组 
   return new AutoConfigurationEntry(configurations, exclusions);
}

是不是有点晕了?其实就是把不合规范和不被允许的剔除,其他保留下来返回出去而已。

spring-factories

不知道在哪找spring-factories?没见过具体是什么内容?

如果是使用Maven做包管理工具的话,在External Libraries下可以找到对应版本的spring-boot-autoconfigure包,包里面有我们的spring.factoriesspring-autoconfigure-metadata.properties

在这里插入图片描述

spring.factories 这个文件存储了spring-boot所有默认支持的待自动装配候选类。

spring-autoconfigure-metadata.properties就是自动装配元数据过滤相关的配置文件。

小结

  1. @Import(AutoConfigurationPackages.Registrar.class),实现是将主配置类(@SpringBootApplication)标注的所有包及子包里面的所有组件扫描到Spring容器当中。
  2. @Import(AutoConfigurationImportSelector.class),实现的是SpringBoot 在启动的时候从类路径下的META-INF/spring.factores中获取@EnableAutoConfiguration指定的值,将这些作为自动配置类导入到容器当中,自动配置类就生效,帮我们进行自动配置的工作。getAutoConfigurationEntry方法是SpringBoot启动时调用的方法,而不是selectImports方法。)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值