spring boot的自动装配原理
spring boot的自动装配原理
自动配置原理解析
源码位置
spring boot自动配置的源码位置在spring-boot-autoconfigure里面
这里可以看到这里已经有rabbitMq的一些默认配置,那么它是怎么把这些配置加载进去的呢 ,带着这个疑问,我们接着往下看。
启动类解析
首先从启动类看,作为一个springboot项目,启动类上有一个注解,必不可少,即@SpringBootApplication,最简单的一个微服务项目, 只需要加一个此注解, 便可启动。这样看来 , 自动配置原理一定和这个注解有着密不可分的联系。
按住Ctrl点击查看启动类MySpringBootApplication上的注解@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 {
@AliasFor(
annotation = EnableAutoConfiguration.class
)
Class<?>[] exclude() default {};
@AliasFor(
annotation = EnableAutoConfiguration.class
)
String[] excludeName() default {};
..................................
注解解析
@SpringBootApplication是一个复合注解或派生注解
其中,包含以下注解
@SpringBootConfiguration:等同与@Configuration,既标注该类是Spring的一个配置类
@EnableAutoConfiguration:SpringBoot自动配置功能开启
按住Ctrl点击查看注解@EnableAutoConfiguration
package org.springframework.boot.autoconfigure;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
可以看到 , 这个注解也是一个派生注解,其中的关键功能由**@Import提供**。其导入的AutoConfigurationImportSelector , 翻译为大白话就是 自动配置导入选择器,大概表示就是这是一个自动配置,然后可以选择性导入我需要的配置文件。那么导入哪些配置文件呢?
源码解析
按住Ctrl点击查看AutoConfigurationImportSelector
源码
这里注意selectImports()
方法,里面有个getAutoConfigurationEntry
(获取自动配置条目), 点进去有个getCandidateConfigurations
(获取候选配置),进入它的代码,发现有个 SpringFactoriesLoader.loadFactoryNames
(spring工厂加载-需要加载的工厂名称),进入它的代码, 发现里面loadFactoryNames
方法里有个loadSpringFactories
(加载spring工厂),进入他的代码,发现这么一行代码
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
恍然醒悟, 原来他是要扫描META-INF文件夹下面的spring.factories文件。
总结一句话就是:
通过SpringFactoriesLoader.loadFactoryNames()扫描所有具有META-INF/spring.factories的jar包。spring-boot-autoconfigure-x.x.x.x.jar里就有一个这样的spring.factories文件。
下方是一些源码截图
spring.factories 文件
- 这个spring.factories文件也是一组一组的key=value的形式,其中一个key是
EnableAutoConfiguration
类的全类名,而它的value是一个xxxxAutoConfiguration的类名的列表,这些类名以逗号分隔,如下图所示: - spring.factories 文件中有关自动配置的配置信息如下:
上面配置文件存在大量的以AutoConfiguration为结尾的类名称,这些类就是存有自动配置信息的类,而
SpringApplication在获取这些类名后再加载
这个@EnableAutoConfiguration
注解通过@SpringBootApplication
被间接的标记在了Spring Boot的启动类上。在SpringApplication.run(…)的内部就会执行selectImports()
方法,找到所有JavaConfig自动配置类的全限定名对应的class,然后将所有自动配置类加载到Spring容器中。
随便进入一个RabbitAutoConfiguration
注意到有个@ConditionalOnClass
,字面以为应用在类上的条件,即自动配置生效的条件
自动配置生效条件
以上可以不难分析出,每一个XxxxAutoConfiguration自动配置类都是在某些特定条件之下才会生效,这些条件的限制在Spring Boot中以注解的形式体现,这也是spring boot区别于之前ssm结构的显著特征。常见的条件注解有如下几项:
@ConditionalOnBean:当容器里有指定的bean的条件下。
@ConditionalOnMissingBean:当容器里不存在指定bean的条件下。
@ConditionalOnClass:当类路径下有指定类的条件下。
@ConditionalOnMissingClass:当类路径下不存在指定类的条件下。
@ConditionalOnProperty:指定的属性是否有指定的值,比如@ConditionalOnProperties(prefix=”xxx.xxx”, value=”enable”, matchIfMissing=true),代表当xxx.xxx为enable时条件的布尔值为true,如果没有设置的情况下也为true。
举例分析
我们以ServletWebServerFactoryAutoConfiguration
为例来分析源码,分析一下全局配置文件中的属性是如何生效,
其中,
@EnableConfigurationProperties(ServerProperties.class)
表示开始配置属性,而他后面的参数时一个ServerProperties类 ,代表加载ServerProperties服务器配置属性类,这里既是spring boot约定大于配置思想的最终实现处。
在这个类上,我们看到了一个非常熟悉的注解:@ConfigurationProperties,它的作用就是从配置文件中绑定属性到对应的bean上,
而@EnableConfigurationProperties负责导入这个已经绑定了属性的bean到spring容器中(见上面截图)。
那么所有其他的和这个类相关的属性都可以在全局配置文件中定义,
也就是说,真正“限制”我们可以在全局配置文件中配置哪些属性的类就是这些XxxxProperties类,
它与配置文件中定义的prefix关键字开头的一组属性是唯一对应的。
至此,我们大致可以了解。在全局配置的属性如:server.port等,通过@ConfigurationProperties注解,
绑定到对应的XxxxProperties配置实体类上封装为一个bean,然后再通过@EnableConfigurationProperties注解导入到Spring容器中。
而诸多的XxxxAutoConfiguration自动配置类,就是Spring容器的JavaConfig形式,作用就是为Spring 容器导入bean,
而所有导入的bean所需要的属性都通过xxxxProperties的bean来获得
默认配置信息
下面是端口号的一个默认配置信息
逻辑图展示
以上繁杂的解析和描述 , 可以参考此图理解(图片来源圣斗士Morty )
总结
以上分析简短描述如下
Spring Boot启动的时候会通过@EnableAutoConfiguration注解找到META-INF/spring.factories配置文件中的所有自动配置类,并对其进行加载,而这些自动配置类都是以AutoConfiguration结尾来命名的,它实际上就是一个JavaConfig形式的Spring容器配置类,它能通过以Properties结尾命名的类中取得在全局配置文件中配置的属性如:server.port,而XxxxProperties类是通过@ConfigurationProperties注解与全局配置文件中对应的属性进行绑定的。