SpringBoot自动装配原理
要先了解SpringBoot自动装配原理我们就得了解@SpringBootApplication注解,他是由三个注解组合成的也就是@ComponentScan(扫描包)和@SpringBootConfiguration(本质就是@Configuration,扫描配置的注解)以及最重要的@EnableAutoConfiguration(自动装配注解)
@ComponentScan
其实也就是Spring的扫描注解,使得@SpringBootApplication实现了自动扫描父包和子包,这样使得我们的APP启动类要放在项目包下面,当然我们放在其他地方也可以,但是需要自己配置扫描路径,
我们以前需要配置包扫描器<context:component-scan base-package="com.test"/>.
@ComponentScan("com.test") 扫描包。
@SpringBootConfiguration
其实SpringBootConfiguration也就是@Configuration注解,他就是javaConfig形式的Spring Ioc容器的配置类使用的@Configuration,本身其实也是一个Ioc容器,以前是使用xml配置的,现在简化开发使用的Bean的来源。
@EnableAutoConfiguration
@EnableAutoConfiguration是一个复合注解,它其中最关键的注解便是@Import(EnableAutoConfigurationImportSelector.class)
和@AutoConfigurationPackage
@AutoConfigurationPackage 里面其实是@Import(Registrar.class)里面存放的其实是包扫描器传过来的,也就是自动注册表。
@Import(EnableAutoConfigurationImportSelector.class)就比较重要了,它一路走下去就是加载了所有在META-INF下面的spring.factories中的自动装配对象,前提是我们导入了对应的启动类。也就是帮助了SpringBoot引用所有符合条件的@Configuration配置到当前SpringBoot所创建的Ioc容器中,就像一个八爪鱼一样借助于Spring原框架的一个工具类:SpringFactoriesLoader。这才使得@EnableAutoConfiguration自动装配的功能实现。
这个注解也是一个派生注解,主要的功能由@Import提供。@Import(AutoConfigurationImportSelector.class)
这是AutoConfigurationImportSelector的主要方法
它又调用了
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry( autoConfigurationMetadata, annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations里面有120个东西就是我们的META-INF/spring.factories
里面的jar包我们继续往下走看它是怎么得到的。
这时候我们看到
List<String> configurations = SpringFactoriesLoader.loadFactoryNames( getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
是不是很熟悉的方法loadFactoryNames这个方法扫描了了所有具有META-INF/spring.factories
的jar包,
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
@EnableAutoConfiguration通过@Import(AutoConfigurationImportSelector.class)调用AutoConfigurationImportSelector中的selectImports调用getAutoConfigurationEntry中的getCandidateConfigurations的SpringFactoriesLoader.loadFactoryNames方法中的
Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
FACTORIES_RESOURCE_LOCATION中存的就是所有带的jar包。
而在spring.factories文件也是一组一组的k-v的形式,k就是EnableAutoConfiguration的全类名,v是xxxxAutoConfiguration的类名的列表,用逗号隔开
这个@EnableAutoConfiguration注解通过@SpringBootApplication被间接的标记在了Spring Boot的启动类上。在SpringApplication.run(…)的内部就会执行selectImports()方法,找到所有JavaConfig自动配置类的全限定名对应的class,然后将所有自动配置类加载到Spring容器中。
自动配置生效
每一个XxxxAutoConfiguration自动配置类都是在某些条件之下才会生效的,这些条件的限制在Spring Boot中以注解的形式体现,常见的条件注解有如下几项
@ConditionalOnBean:当容器里有指定的bean的条件下。 @ConditionalOnMissingBean:当容器里不存在指定bean的条件下。 @ConditionalOnClass:当类路径下有指定类的条件下。 @ConditionalOnMissingClass:当类路径下不存在指定类的条件下。
在ServletWebServerFactoryAutoConfiguration
类上,有一个@EnableConfigurationProperties
注解:开启配置属性,而它后面的参数是一个ServerProperties类,这就是习惯优于配置的最终落地点。
在这个类上有个ConfigurationProperties注解,他的作用就是从配置文件中绑定属性到对应的bean上,而@EnableConfigurationProperties
负责导入已经绑定了属性的bean到Spring容器中,那么所有和他相关的属性都可以在全局配置文件中定义,限制全局配置文件中配置那些属性就是XxxxProperties类,他与配置文件中定义的prefix关键字开头的一组属性是唯一对应的。
全局配置文件中的属性通过@ConfigurationProperties注解绑定到对应的Properties配置实体类上封装为一个bean,再通过@EnableConfigurationProperties注解导入到Spring容器中。
而诸多的XxxxAutoConfiguration自动配置类,就是Spring容器的JavaConfig形式,作用就是为Spring 容器导入bean,而所有导入的bean所需要的属性都通过xxxxProperties的bean来获得。
面试解答
Spring Boot启动的时候会通过@EnableAutoConfiguration注解找到META-INF/spring.factories配置文件中的所有自动配置类,并对其进行加载,而这些自动配置类都是以AutoConfiguration结尾来命名的,它实际上就是一个JavaConfig形式的Spring容器配置类,它能通过以Properties结尾命名的类中取得在全局配置文件中配置的属性如:server.port,而XxxxProperties类是通过@ConfigurationProperties注解与全局配置文件中对应的属性进行绑定的。
当然不是所有的jar包我们都用的上,当我们导入了对应的启动器他才能供我们使用详情看这里
这些是条件注解,只有导入了启动类,条件注解检测到了有对应的类,这个类才会自动化配置。
最后奉上大图