1.

基于 @SpringBootApplication 注解实现自动配置的基本过程和原理


1)@SpringBootApplication

创建项目会默认生成,在启动类上会看到这个注解。

位于 spring-boot-autoconfigure 工程的org.springframework.boot.autoconfigure 包中。

由3个注解组成:@SpringBootConfiguration、@EnableAutoConfiguration 和 @ComponentScan

可以通过 exclude 和 excludeName 属性来配置不需要实现自动装配的类或类名,也可以通过 scanBasePackages 和 scanBasePackageClasses 属性来配置需要进行扫描的包路径和类路径。


2)@ComponentScan

批量扫描Bean并注入到容器中


3)@SpringBootConfiguration

提供JavaConfig配置类的实现


4)@EnableAutoConfiguration

在这个注解中有两个注解:@AutoConfigurationPackage@Import(AutoConfigurationImportSelector.class)


5)@Import

属性中可以设置需要引入的类名根据该类的不同类型,Spring 容器针对 @Import 注解有以下四种处理方式:

  • 如果该类实现了 ImportSelector 接口,Spring 容器就会实例化该类,并且调用其 selectImports 方法;

  • 如果该类实现了 DeferredImportSelector 接口,则 Spring 容器也会实例化该类并调用其 selectImports方法。DeferredImportSelector 继承了 ImportSelector,区别在于 DeferredImportSelector 实例的 selectImports 方法调用时机晚于 ImportSelector 的实例,要等到 @Configuration 注解中相关的业务全部都处理完了才会调用;

  • 如果该类实现了 ImportBeanDefinitionRegistrar 接口,Spring 容器就会实例化该类,并且调用其 registerBeanDefinitions 方法;

  • 如果该类没有实现上述三种接口中的任何一个,Spring 容器就会直接实例化该类。

6) AutoConfigurationPackages.Registrar 类

这个类是@AutoConfigurationPackage注解中@Import(AutoConfigurationPackages.Registrar.class)注解里使用到的类,遵循第三种情况,实现ImportBeanDefinitionRegistrar接口,并重写registerBeanDefinitions方法。这个方法的逻辑是先判断整个 Bean 有没有被注册,如果已经注册则获取 Bean 的定义,通过 Bean 获取构造函数的参数并添加参数值;如果没有,则创建一个新的 Bean 的定义,设置 Bean 的类型为 AutoConfigurationPackages 类型并进行 Bean 的注册


7)AutoConfigurationImportSelector类

@EnableAutoConfiguration@Import(AutoConfigurationImportSelector.class)使用到

实现DeferredImportSelector接口,符合第二规则

负责从各种配置项中找到需要导入的具体配置类

依赖的最关键组件就是 SpringFactoriesLoader


2.

上面的东西总结就是:注册Bean+导入配置类。接着就提到了JDK 中的 SPI 机制,原文这样说的:

JDK 提供了用于服务查找的一个工具类 java.util.ServiceLoader 来实现 SPI 机制。当服务提供者提供了服务接口的一种实现之后,我们可以在 jar 包的 META-INF/services/ 目录下创建一个以服务接口命名的文件,该文件里配置着一组 Key-Value,用于指定服务接口与实现该服务接口具体实现类的映射关系。而当外部程序装配这个 jar 包时,就能通过该 jar 包 META-INF/services/ 目录中的配置文件找到具体的实现类名,并装载实例化,从而完成模块的注入。SPI 提供了一种约定,基于该约定就能很好地找到服务接口的实现类,而不需要在代码里硬编码指定。

我认为的意思就是:

接口实例化使用哪个实现类,不在代码里指定,在文件里指定。有哪些使用场景吗?有用过的留言说说。

SpringFactoriesLoader用的就是SPI机制,查找所有 META-INF/spring.factories 文件夹中的配置文件并把 Key 为 EnableAutoConfiguration 所对应的配置项通过反射实例化为配置类并加载到容器中。

流程是跟着看了一遍,但是没啥感觉,平时还是在配置文件里写配置,看来还需要更多的经验啊。


3.

关于默认配置,提到了一个注解@ConditionalOn,常见的一些:

@ConditionalOnProperty:只有当所提供的属性属于 true 时才会实例化 Bean

@ConditionalOnBean:只有在当前上下文中存在某个对象时才会实例化 Bean

@ConditionalOnClass:只有当某个 Class 位于类路径上时才会实例化 Bean

@ConditionalOnExpression:只有当表达式为 true 的时候才会实例化 Bean

@ConditionalOnMissingBean:只有在当前上下文中不存在某个对象时才会实例化 Bean

@ConditionalOnMissingClass:只有当某个 Class 在类路径上不存在的时候才会实例化 Bean

@ConditionalOnNotWebApplication:只有当不是 Web 应用时才会实例化 Bean


自动配置可以提高系统的扩展性,许是没有太多的架构设计经验,限制了我的思路,多多学习吧。