一、SpringBoot的自动配置原理

SpringBoot 的自动化配置让我们的开发彻底远离了 Spring 繁琐的各种配置,让我们专注于开发,但是SpringBoot 的自动化配置是怎么实现的呢?下面为你揭开 SpringBoot 自动化配置的神秘面纱。

所以今天来讲讲SpringBoot是如何实现自动配置的~

1.1三个重要的注解

我们可以发现,在使用​​main()​​​启动SpringBoot的时候,必不可少的注解​​@SpringBootApplication​

SpringBoot的自动配置原理_ide

我们可以点击进去​​@SpringBootApplication​​注解中看看,它其实是由三个注解组成的组合注解:

SpringBoot的自动配置原理_ide_02

  • ​@SpringBootConfiguration​​ :底层是Configuration注解,说白了就是支持JavaConfig的方式来进行配置(使用Configuration配置类等同于XML文件)。
  • ​@EnableAutoConfiguration​​:开启自动配置功能
  • ​@ComponentScan​​:扫描注解,默认是扫描当前类下的package。将@Controller/@Service/@Component/@Repository等注解加载到IOC容器中。

1.2重点@EnableAutoConfiguration

我们知道SpringBoot可以帮我们减少很多的配置,也肯定听过“约定大于配置”这么一句话,那SpringBoot是怎么做的呢?其实靠的就是**@EnableAutoConfiguration**注解。

简单来说,这个注解可以帮助我们自动载入应用程序所需要的所有默认配置

如果你的类路径下有​​tomcat-embedded.jar​​包,那么你很可能就需要TomcatServletWebServerFactory

我们点进去看一下,发现有两个比较重要的注解:

SpringBoot的自动配置原理_ide_03

  • ​@AutoConfigurationPackage​​:自动配置包
  • ​@Import​​:给IOC容器导入组件

1.2.1 @AutoConfigurationPackage

网上将这个**@AutoConfigurationPackage注解解释成自动配置包**,我们也看看​​@AutoConfigurationPackage​​里边有什么:

SpringBoot的自动配置原理_加载_04

我们可以发现,依靠的还是​​@Import​​注解,再点进去查看,我们发现重要的就是以下的代码:

SpringBoot的自动配置原理_sed_05

默认的情况下就是将:主配置类(​​@SpringBootApplication​​)的所在包及其子包里边的组件扫描到Spring容器中。

  • 看完这句话,会不会觉得,这不就是ComponentScan的功能吗?这俩不就重复了吗?

我开始也有这个疑问,直到我看到文档的这句话:

it will be used when scanning for code ​​@Entity​​ classes. It is generally recommended that you place EnableAutoConfiguration (if you’re not using @SpringBootApplication) in a root package so that all sub-packages and classes can be searched.

比如说,你用了Spring Data JPA,可能会在实体类上写​​@Entity​​​注解。这个​​@Entity​​​注解由​​@AutoConfigurationPackage​​​扫描并加载,而我们平时开发用的​​@Controller/@Service/@Component/@Repository​​​这些注解是由​​ComponentScan​​来扫描并加载的。

  • 简单理解:这二者扫描的对象是不一样的。

1.2.2回到Import

我们发现它使用了 Spring 框架提供的 @Import 注解注入了注册 Bean 的配置类,在往下分析前,不妨先了解一下这个 @Import 注解,在我们平时使用 Spring 框架的 Enable* 类注解时,发现它们都有一个共同的特点,就是都有一个 @Import 注解,用来导入配置类,这些配置方式又分为三种类型:

  • 直接导入配置类:@Import({xxxConfiguration.class})
  • 依据条件选择配置类:@Import({xxxSelector.class})
  • 动态注册 Bean:@Import({xxxRegistrar.class})

我们回到​​@Import(AutoConfigurationPackages.Registrar.class)​​​这句代码上,再点进去​​AutoConfigurationPackages.Registrar.class​​看看具体的实现是什么:

/**
* {@link ImportBeanDefinitionRegistrar} to store the base package from the importing
* configuration.
*/
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));
}

}

1.3总结

@SpringBootApplication等同于下面三个注解:

  • @SpringBootConfiguration
  • @EnableAutoConfiguration
  • @ComponentScan

其中@EnableAutoConfiguration是关键(启用自动配置),内部实际上就去加载​​META-INF/spring.factories​​文件的信息,然后筛选出以EnableAutoConfiguration为key的数据,加载到IOC容器中,实现自动配置功能!