前言
不论在工作中,亦或是求职面试,Spring Boot 已经成为我们必知必会的技能项。除了某些老旧的政府项目或金融项目持有观望态度外,如今的各行各业都在飞速的拥抱这个已经不是很新的Spring启动框架。
当然,作为 Spring Boot 的精髓,自动配置原理的工作过程往往只有在"面试"的时候才能用得上,但是如果在工作中你能够深入的理解Spring Boot的自动配置原理,将无往不利。
Spring Boot 的出现,得益于"约定优于配置"
的理念,没有繁琐的配置、难以集成的内容(大多数流行第三方技术都被集成),这是基于 Spring 4.x 提供的按条件配置 Bean 的能力。
1.Spring Boot的配置文件
初识 Spring Boot 时我们就知道,Spring Boot 有一个全局配置文件:application.properties 或 application.yml
我们的各种属性都可以在这个文件中进行配置,最常配置的比如:server.port
、logging.level.*
等等,然而我们实际用到的往往只是很少的一部分,那么这些属性是否有据可依呢?答案当然是肯定的,这些属性都可以在官方文档中查找到的,请点击我,我是官方文档。
除了官方文档为我们提供了大量的属性解释,我们也可以使用 IDE 的相关提示功能,比如IDEA的自动提示,如下所示:
以上,就是 Spring Boot 的配置文件的大致使用方法,其实都是些题外话。
那么问题来了:这些配置是如何在 Spring Boot 项目中生效的呢?那么接下来,就需要聚焦本篇博客的主题:自动配置工作原理分析。
2.Spring Boot 自动配置原理分析
我们在之前已经对Spring Boot 启动中使用到的 @SpringBootApplication 注解有过一个简短的了解,你可以参考这篇内容:@SpringBootApplication注解分析。看完这篇文章,我们就知道了 Spring Boot 关于自动配置的源码都是在 spring-boot-autoconfigure-x.x.x.x.jar 中:
当然,自动配置原理的相关描述,官方文档貌似是没有提及。不过我们不难猜出,Spring Boot 的启动类上有一个@SpringBootApplication注解,这个注解是Spring Boot 项目必不可少的注解。自动配置原理就是和这个注解有着千丝万缕的联系!
@SpringBootApplication是一个复合注解,该注解被@EnableAutoConfiguration 注解,该注解的意识就是:开启自动配置
,其定义如下:
这个注解也是一个符合注解,我们关键来了解@Import
这个注解,它的意思就是通过AutoConfigurationImportSelector
这个类来进行相关的操作。我们发现该类中有重写了一个 selectImports()方法
,它是通过 SpringFactoriesLoader.loadFactoryNames() 的方式,扫描所有位于META-INF/spring.factories
文件下的jar包。在 META-INF 路径下,我们一共看到了两个spring.factories 文件。如下图所示:
关于Spring Boot 自动配置的相关项,是在 spring-boot-autoconfigure-x.x.x.x.jar
这个jar包下,如图所示。
这个 spring.factories 文件中的内容,也是以我们常见的 key=value
的形式,其中一个key是 EnableAutoConfiguration 类的全类名,而它的value是一个xxxxAutoConfiguration 的类名的列表,这些类名以逗号分隔,如下图所示:
这个 @EnableAutoConfiguration 注解通过@SpringBootApplication 被间接的标记在了Spring 的启动类上。
在执行 SpringApplication.run(…) 的内部就会执行selectImports()方法,找到所有 JavaConfig 自动配置类的全限定名对应的 class,然后将所有自动配置类加载到Spring容器中。
3.如何使自动配置自动生效
接下来,我们就对 xxxAutoConfiguration 这些自动配置类进行分析,看看他们是如何自动生效的,我们在每一个 xxxAutoConfiguration 类上都会看到有很多注解的存在。在此处,我们以:HttpEncodingAutoConfiguration 类
进行分析。
@Configuration
@EnableConfigurationProperties(HttpEncodingProperties.class)
@ConditionalOnWebApplication
@ConditionalOnClass(CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {
private final HttpEncodingProperties properties;
public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
this.properties = properties;
}
@Bean //给容器中添加一个组件,这个组件的某些值需要从properties中获取
@ConditionalOnMissingBean(CharacterEncodingFilter.class) //判断容器没有这个 CharacterEncodingFilter 组件
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
return filter;
}
}
首先对这几个注解进行一番介绍:
@Configuration //表示当前类是一个配置类
@EnableConfigurationProperties(HttpEncodingProperties.class) //启动指定类的ConfigurationProperties功能;将配置文件中对应的值和HttpEncodingProperties绑定起来;并把HttpEncodingProperties加入到ioc容器中(HttpEncodingProperties类有被@ConfigurationProperties 注解)
@ConditionalOnWebApplication //判断当前应用是否是web应用,如果是,当前配置类生效
@ConditionalOnClass(CharacterEncodingFilter.class) //判断当前项目有没有这个(CharacterEncodingFilter;SpringMVC中进行乱码解决的过滤器)
@ConditionalOnProperty(prefix = “spring.http.encoding”, value = “enabled”, matchIfMissing = true) //判断配置文件中是否存在某个配置 spring.http.encoding.enabled;如果不存在,判断也是成立的。即使我们配置文件中不配置pring.http.encoding.enabled=true,也是默认生效的;
通过如上多个注解的层层判断,便能够决定当前配置文件是否生效。只要不满足其中一个条件,都是不会被自动配置到 Spring 容器中的。
4.如何查看哪些自动配置已经加载到 Spring 容器
既然 Spring Boot 已经为我们整合了N多场景下的自动配置类。但是在容器启动之后,我们怎么来查看Spring 容器中有哪些被自动配置了呢?这是后我们就用到了 Spring Boot 为我们提供的 debug功能
。
我们可以在 application.yml/properties 主配置文件中,通过 debug: true
的方式来开启 Debug 模式,来让控制台打印自动配置报告。在项目启动时,它会为我们提供一个 AUTO-CONFIGURATION REPORT(自动配置报告)
,在这份报告中,我们便能够一目了然的看到,哪些组件已经加载到 Spring 容器中。
自动报告内容很多,此处附部分内容:
=========================
AUTO-CONFIGURATION REPORT
=========================
Positive matches:(已启用的配置)
-----------------
DispatcherServletAutoConfiguration matched:
- @ConditionalOnClass found required class 'org.springframework.web.servlet.DispatcherServlet'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
- @ConditionalOnWebApplication (required) found StandardServletEnvironment (OnWebApplicationCondition)
DispatcherServletAutoConfiguration.DispatcherServletConfiguration matched:
- @ConditionalOnClass found required class 'javax.servlet.ServletRegistration'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
- Default DispatcherServlet did not find dispatcher servlet beans (DispatcherServletAutoConfiguration.DefaultDispatcherServletCondition)
DispatcherServletAutoConfiguration.DispatcherServletRegistrationConfiguration matched:
- @ConditionalOnClass found required class 'javax.servlet.ServletRegistration'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
- DispatcherServlet Registration did not find servlet registration bean (DispatcherServletAutoConfiguration.DispatcherServletRegistrationCondition)
Negative matches:(未启用的配置)
-----------------
ActiveMQAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required classes 'javax.jms.ConnectionFactory', 'org.apache.activemq.ActiveMQConnectionFactory' (OnClassCondition)
AopAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required classes 'org.aspectj.lang.annotation.Aspect', 'org.aspectj.lang.reflect.Advice' (OnClassCondition)
ArtemisAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required classes 'javax.jms.ConnectionFactory', 'org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory' (OnClassCondition)
本文部分文字内容,摘自:https://blog.csdn.net/u014745069/article/details/83820511
博主写作不易,来个关注呗
求关注、求点赞,加个关注不迷路 ヾ(◍°∇°◍)ノ゙
博主不能保证写的所有知识点都正确,但是能保证纯手敲,错误也请指出,望轻喷 Thanks♪(・ω・)ノ