本文有参考大佬博客写的,有什么不对的地方,大佬们请指出。
今天研究一下SpringBoot走动装配的原理,通过分析注解和Debug来大致了解一下
1、首先肯定就是找到 SpringBoot 的主启动类,在这个主启动类中有一个 @SpringBootApplication
的注解,SpringBoot 通过这个注解来说明这个类是主启动类,通过执行类中的main方法来启动 SpringBoot 项目
在main方法里面会执行一个run方法:
大概意思就是会使用一个默认的配置来启动。
2、接着看这个注解里面有什么。
这里面有三个核心注解:@SpringBootConfiguration、@EnableAutoConfiguration 这两个核心注解
这个注解里面只有 @Configuration
这个注解,所以说 @SpringBootConfiguration 这个注解只是标注这是 Spring 容器的一个配置类。这个配置类也是 Spring 的一个组件
可以看到这个注解里面主要有两个注解,分别是 @AutoConfigurationPackage
、@Import(AutoConfigurationImportSelector.class)
,先看 @AutoConfigurationPackage
点进这个注解
它会通过 @Import 注解导入一个 AutoConfigurationPackages 类下的一个静态内部类 Registrar.class
,继续点进去。
有一个方法,大概就是说注册定义的Bean,我对这个方法打断点Debug一下:发现他要扫描的包是我的主启动类,这时候就大概知道SpringBoot 就是通过这个注解来扫描主启动类下的包和子包下的所有组件并加载到 Spring 容器。那这个metadata又是什么呢,我们有应该从哪加载这些组件资源呢。接下来就有 @Import(AutoConfigurationImportSelector.class)
点进 AutoConfigurationImportSelector 这个类中可以看到 它有一个 selectImports() 方法,调用了 getAutoConfigurationEntry() 方法,点进这个方法。
我对这个方法打个断点测试一下:发现当它走完 getCandidateConfigurations()
方法的时候,就多了很多的 configurations,这些都是自动配置类的全限定名。
这个时候就大概知道了,SpringBoot 通过@Import(AutoConfigurationImportSelector.class)
这个注解加载了我们 Spring 容器需要的所有配置类,可以知道这些配置类是通过getCandidateConfigurations()
方法加载的,所以继续进入到这个方法:
也就是说 AutoConfigurationImportSelector的selectInports() 方法通过 SpringFactoriesLoader.loadFactoryNames() 方法扫描到 META-INF/spring.factories 的jar包,并且将需要的自动配置包加载到 Spring 容器中,找到这个 spring.factories 文件:
所以就在这里找到了自动配置类并且加载到了 Spring 容器中,完成自动配置类的加载。
每一个 xxxAutoConfiguration 自动配置类都是在某些条件之下才会生效的,这些条件的限制在Spring Boot中以注解的形式体现,常见的条件注解有如下几项:
@ConditionalOnBean:当容器里有指定的bean的条件下。
@ConditionalOnMissingBean:当容器里不存在指定bean的条件下。
@ConditionalOnClass:当类路径下有指定类的条件下。
@ConditionalOnMissingClass:当类路径下不存在指定类的条件下。
@ConditionalOnProperty:指定的属性是否有指定的值,比如
@ConditionalOnProperties(prefix=”xxx.xxx”, value=”enable”, matchIfMissing=true),代表当xxx.xxx为enable时条件的布尔值为true,如果没有设置的情况下也为true。
以 WebMvcAutoConfiguration 为例,看看 spring.web.xxx 是如何生效的(当然不配置也会有默认值)
在 WebMvcAutoConfiguration 中有一个静态内部类标注了 @EnableConfigurationProperties(WebProperties.class)
,这个注解就是开启自动配置属性,后面的参数是一个 WebProperties 类,这就是 约定大于配置的最终落脚点
在这个类上,有一个非常熟悉的注解:@ConfigurationProperties,它的作用是从配置文件中绑定属性到对应的 Bean 上,而 @EnableConfigurationProperties这个就是负责将绑定了属性的 Bean 加载到 Spring 容器中。那么所有其他的和这个类相关的属性都可以在全局配置文件中定义,也就是说,真正“限制”我们可以在全局配置文件中配置哪些属性的类就是这些 xxxProperties 类,它与配置文件中定义的 prefix 关键字开头的一组属性是唯一对应的。
至此,大致可以了解,在全局配置的属性如:spring.web.xxx等,通过 @ConfiguratuiobProperties 注解,绑定到对应的 xxxProperties 配置实体类上封装为一个 Bean,然后通过 @EnableConfigurationProperties 注解导入到 Spring 容器中。
所有的 xxxAutoConfiguration 自动配置类就是 Spring 容器的 JavaConfig 形式,作用就是将 Bean 导入 Spring 容器,而所有的 Bean 所需要的属性是通过 xxxProperties 的 Bean 来获得。
Spring Boot启动的时候会通过@EnableAutoConfiguration注解找到META-INF/spring.factories配置文件中的所有自动配置类,并对其进行加载,而这些自动配置类都是以AutoConfiguration结尾来命名的,它实际上就是一个JavaConfig形式的Spring容器配置类,它能通过以Properties结尾命名的类中取得在全局配置文件中配置的属性如:server.port,而XxxxProperties类是通过@ConfigurationProperties注解与全局配置文件中对应的属性进行绑定的。
其实核心就是 @EnableAutoConfiguration
这个注解,这个注解扫描了主启动类所在包和导入了 spring.factories 中的所有的 xxxAutoConfiguration 配置类。通过 @Conditionalxxx 来使自动配置生效。
还有就是 xxxProperties 就是封装配置文件中的属性的,给 Bean 属性赋值,比如说 spring.web.xxx 的属性
xxxAutoConfiguration 就是 Spring 的 JavaConfig 自动配置类,目的是给 Spring 容器添加 组件
参考文章1
参考文章2