SpringBoot系列(一):第3章深入探索 SpringBoot 的自动配置原理

前言

在之前的文章中我们体会了使用SpringBoot快速搭建一个web工程是多么的方便,没有复杂的xml配置,只需要添加所需的开发场景就能快速的进行开发。在本节里将剖析SpringBoot 自动配置 背后的故事。。。

 

@SpringBootApplication

打开@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) })
public @interface SpringBootApplication {

    // 排除不需要的应用场景
    // 1、通过xxx.class来排除
	/**
	 *  auto-configuration classes 
	 * @return the classes to exclude
	 */
	@AliasFor(annotation = EnableAutoConfiguration.class)
	Class<?>[] exclude() default {};

    // 2、通过类的名称排除
	/**
	 * Exclude specific auto-configuration class names 
	 * @return the class names to exclude
	 * @since 1.3.0
	 */
	@AliasFor(annotation = EnableAutoConfiguration.class)
	String[] excludeName() default {};
    
    // 组件扫描

	// 1、根据包名来扫描组件,并将组件添加到SpringIOC容器中
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
	String[] scanBasePackages() default {};

    // 2、根据包名+类名称来扫描组件,并将组件添加到SpringIOC容器中
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
	Class<?>[] scanBasePackageClasses() default {};

}

@Configuration注解分析

只要一个类上标注了@Configuration 那这个类相当于就是一个Spring中xml配置文件。

 

@ComponentScan 注解分析

若不标注扫包的范围,默认扫描当前类所在的包以及子包下边的标有@Component的类。并把相关的Bean的定义批量加载到Spring IOC 容器中。

 

@EnableAutoConfiguration

打开该注解的定义,如下所示

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

	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    // 根据xxx.class 来排除
	Class<?>[] exclude() default {};
    

    // 根据类名来排除
	String[] excludeName() default {};

}

在上述代码块,

@Import 注解引入 AutoConfigurationImportSelector.class。而@Import注解在Spring中作用就是用于导入JavaConfig配置类即类上标注@Configuration的类,我们习惯称之为配置类(哈哈,这是国际惯例)。

从AutoConfigurationImportSelector.class 类名我们可以看出这个类就是一种选择器,负责从各种配置中找到需要导入的具体配置类。而其中依赖了一个组件SpringFactoriesLoader。

而这个组件SpringFactoriesLoader是如何工作的呢?首先我们就要熟悉或者了解一下JDK中SPI(Service Provider Interface)机制,JDK提供了实现服务查找的一个工具类java.util.ServiceLoader 来实现SPI机制。当服务提供者提供了服务接口之后,wom我们可以在其jar包内的META-INF/services/ 目录下创建一个以服务接口命名的文件,该文件中配置了一组key-value,用于指定服务接口与实现服务接口的某个具体实现类之间的映射关系。因此,当外部的应用程序加载该jar时候,就能通过META-INF/services/ 目录中的配置文件,从而就能找到接口的某个具体实现类名称,从而装载它并将其实例化完成模块的注入。SPI机制原理图如下

SpringBoot系列(一):第3章深入探索 SpringBoot 的自动配置原理

 

由于上述的 SPI 机制,与其说是一种机制倒不如说是一种约定,基于该约定就能很好的找到服务接口的实现类,从而让接口与接口的实现类们解耦了。

SpringFactoriesLoader 而这个组件就是采用 SPI 的设计思路,不同点就是其接口的命名文件即定义服务接口与服务接口实现类之间映射关系的文件是存放在 META-INF/spring.factories 中。其key就是EnableAutoConfiguration,并将key所对应的value也就是接口的实现类们通过java反射机制实例化为配置类并将其装载到Spring IOC 容器中,spring.factories 部分配置如下

 

SpringBoot系列(一):第3章深入探索 SpringBoot 的自动配置原理

 

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

# Auto Configuration Import Listeners
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener

# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnClassCondition

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\

。。。。。。。

org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.EnableAutoConfiguration= xxxxx,xxxx,xxx 很多

这个 key: org.springframework.boot.autoconfigure.EnableAutoConfiguration 所对应的的values,即很多实现类。这些配置在SpringBoot启动过程中就会加载了进入运行时环境实现了自动化配置。但是并不是所有的开发场景都会生效即该接口的实现类并不会完全加载到运行时环境中,只有导入的某个特定的开发场景时,EnableAutoConfiguration 所对应的 这个开发场景才会生效。比如我导入 spring-boot-starter-web 这个开发场景,那么 EnableAutoConfiguration 所对应的 关于web开发场景的接口实现类就会生效。从而就是实现了自动配置。

至此,SpringBoot自动配置原理剖析完毕,大佬们若觉得还行,请为我点赞。。