以基于maven
的和缺省配置的Spring Boot + Spring Web MVC
应用项目为例观察Spring Boot
自动配置机制如何工作 :
1.pom.xml
引入依赖spring-boot-autoconfigure
// 以下pom.xml 对 spring-boot-autoconfigure 的依赖引入是隐含的,不是直接引入。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>andy.tut.springboot</groupId>
<artifactId>zero</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.8.RELEASE</version>
</parent>
<dependencies>
// 缺省配置 Springboot Web 项目的直接依赖,
// 隐含的依赖 :
// org.springframework.boot:spring-boot-starter
// |--org.springframework.boot:spring-boot
// |--org.springframework.boot:spring-boot-autoconfigure
// |--org.springframework.boot:spring-boot-starter-logging
// |--org.springframework:spring-core
// |--org.yaml:snakeyaml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
通过引入依赖spring-boot-autoconfigure
,相应的jar包会出现在Springboot
应用运行时的classpath中。
2.Spring Boot
应用入口类使用注解@SpringBootApplication
@SpringBootApplication
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
注解@SpringBootApplication
隐含了spring-boot-autoconfigure
的注解@EnableAutoConfiguration
,
而注解@EnableAutoConfiguration
上又有注解@Import(EnableAutoConfigurationImportSelector.class)
。
这个@Import(EnableAutoConfigurationImportSelector.class)
在Springboot
应用启动时做的就是spring-boot-autoconfigure
被设计用来完成的工作:auto configure
, 自动配置。
// 注解链
@SpringBootApplication
=>@EnableAutoConfiguration
=> @Import(EnableAutoConfigurationImportSelector.class)
3.应用启动时ConfigurationClassPostProcessor
的注册
Springboot
应用在启动时,会创建一个ApplicationContext
上下文实例。如果是Web应用,该上下文实例会使用类 AnnotationConfigEmbeddedWebApplicationContext
来创建;否则使用类AnnotationConfigApplicationContext
来创建。
不管是以上两种情况中的哪一种,相应的上下文类实例在创建时都会创建一个AnnotatedBeanDefinitionReader
实例用于读取注解方式的Bean定义,而在创建这个AnnotatedBeanDefinitionReader
实例的过程中,它注册了一个 ConfigurationClassPostProcessor Bean
定义到容器,这是一个BeanFactoryPostProcessor
,更明确地讲,它是一个BeanDefinitionRegistryPostProcessor
。
ConfigurationClassPostProcessor
被设计用来发现所有的配置类和相关的Bean定义并注册到容器,它在所有BeanFactoryPostProcessor
中具备最高执行优先级,因为其他BeanFactoryPostProcessor
需要基于注册了Bean定义工作。
spring-boot-autoconfigure
自动配置的"自动"属性,主要就是通过这个机制来体现的 :
-
Spring
容器启动时会在任何bean被使用前对该bean应用所有注册到容器中的BeanDefinitionRegistryPostProcessor
; -
ConfigurationClassPostProcessor
正是这样一个BeanDefinitionRegistryPostProcessor
,并且在容器构造最早期就被注册了进来; -
ConfigurationClassPostProcessor
的工作就是发现classpath
中所有的符合条件的配置类并注册相应的bean定义,也就是执行了所谓的自动配置任务; -
spring-boot-autoconfigure
包在开发阶段已经被引入了应用的classpath中。
4.应用启动时spring-boot-autoconfigure
自动配置任务的执行
spring-boot-autoconfigure
被设计用来在springboot
启动过程中完成自动配置,这个自动配置通过上述设置后,会在springboot
启动过程中,具体的来讲,是在以下位置被完成 :
SpringApplication.run()
=> refreshContext()
=> AbstractApplicationContext.refresh()
=> invokeBeanFactoryPostProcessors()
=> ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry()
=> processConfigBeanDefinitions()
=> ConfigurationClassParser.parse()
=> processDeferredImportSelectors()
=> AutoConfigurationImportSelector.selectImports()
下面是spring-boot-autoconfigure jar包内文件的结构。
spring-boot-autoconfigure jar包的文件结构
├─META-INF
│ spring-autoconfigure-metadata.properties
│ spring.factories
│
└─org
└─springframework
└─boot
└─autoconfigure
有几个很重要的信息 :
-
META-INF/spring-autoconfigure-metadata.properties
包含了自动配置元数据。 -
META-INF/spring.factories
使用属性org.springframework.boot.autoconfigure.EnableAutoConfiguration
定义了哪些类是自动配置类,使用属性org.springframework.boot.autoconfigure.AutoConfigurationImportFilter
定义了哪些自动配置导入过滤器会被应用,缺省情况下,只有一个过滤器会被应用,那就是OnClassCondition
。 -
在包
org.springframework.boot.autoconfigure
存在很多@Configuration
注解的候选配置类。
AutoConfigurationImportSelector.selectImports()
在执行时 :
-
从
spring-autoconfigure-metadata.properties
属性文件中提取自动配置元数据AutoConfigurationMetadata
; -
获取
spring.factories
属性文件中属性org.springframework.boot.autoconfigure.EnableAutoConfiguration
定义的所有配置类作为候选配置类; -
然后,获取
spring.factories
属性文件中属性org.springframework.boot.autoconfigure.AutoConfigurationImportFilter
定义的过滤器,缺省是一个 :org.springframework.boot.autoconfigure.condition.OnClassCondition
-
对所有的候选配置类在自动配置元数据上应用所发现的过滤器,其实缺省情况下就一个,就是
OnClassCondition
,也就是利用每个候选配置类上的注解@ConditionalOnClass
, 来看这个候选配置类是否需要被应用。 -
selectImports()
会返回所有需要被应用的配置类(注解@ConditionalOnClass
条件被满足),ConfigurationClassPostProcessor.postProcessBeanFactory()
会将识别这些配置类中定义的bean并将它们注册到容器。
具体的处理逻辑可以参考 :