Loading...
墨滴

楼仔

2021/07/18  阅读:68  主题:橙心

【Spring Boot系列3】自动化配置详解

主要讲解SpringBoot自动化配置原理,结合系列1的内容,可以形成SpringBoot原理知识体系闭环。

SpringBoot只是个框架,前期我主要了解该框架内部的执行原理,然后掌握SpringBoot的基本使用姿势,就达到我的初步目标,后面打算结合公司具体的项目,然后再慢慢学习。

基本介绍

一般认为,SpringBoot 微框架从两个主要层面影响 Spring 社区的开发者们:

  • 基于 Spring 框架的“约定优先于配置(COC)”理念以及最佳实践之路。
  • 提供了针对日常企业应用研发各种场景的 spring-boot-starter 自动配置依赖模块,如此多“开箱即用”的依赖模块,使得开发各种场景的 Spring 应用更加快速和高效。

我理解,一个就是去XML配置,一个就是自动化配置。

SpringBoot 提供的这些“开箱即用”的依赖模块都约定以 spring-boot-starter- 作为命名的前缀,常用的如下:

  • spring-boot-starter-logging
  • spring-boot-starter-web
  • spring-boot-starter-jdbc
  • spring-boot-starter-aop
  • spring-boot-starter-security
  • spring-boot-starter-actuator

并且皆位于 org.springframework.boot 包或者命名空间下(虽然 SpringBoot 的官方参考文档中提到不建议大家使用 spring-boot-starter- 来命名自己写的类似的自动配置依赖模块,但实际上,配合不同的 groupId,这不应该是什么问题)。

那么自动化配置,在SpringBoot的执行流程中处于哪个环节呢?它又是怎么自动化加载配置的呢?其实我们在之前的文章中,就可以找到部分答案。

知识回顾

@EnableAutoConfiguration

在文章《【Spring Boot系列1】一文带你了解Spring Boot(上)》,我们介绍过@EnableAutoConfiguration注解,@EnableAutoConfiguration 是借助 @Import 的帮助,将所有符合条件的 @Configuration 配置都加载到当前 SpringBoot 创建并使用的 IoC 容器,就跟一只“八爪鱼”一样:

执行流程

在文章《【Spring Boot系列1】一文带你了解Spring Boot(下)》,我们讲解了SpringApplication.run执行流程,第9步描述“最核心的一步,将之前通过 @EnableAutoConfiguration 获取的所有配置以及其他形式的 IoC 容器配置加载到已经准备完毕的 ApplicationContext。”

所以自动化配置就是在“创建好上下文”之后,在“通知应用装载上下文”之前进行的,它做了啥事情呢?其实就是将自动化配置信息完善到上下文中,而这个自动加载的过程,主要就靠@EnableAutoConfiguration。所以你也可以理解,通过该注解给Spring提供一个完善的上下文环境。

这里讲述了自动化配置的执行位置、执行方式、执行后的结果,那最后执行依赖的形式是什么呢?具体有啥用呢?大家可能还是觉得有些抽象,举个栗子:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.2</version>
</dependency>

大白话概括一下,其实就是把这些东东加载到SpringBoot中,方便大家使用,比如jdbc、web、log、security等等,我把他们理解为“扩展功能”,感觉更贴切一些,支持“自动加载”和“开箱即用”。

自动化配置

自动化配置流程

  1. SpringBoot启动的时候加载主配置类,开启了自动配置功能 @EnableAutoConfiguration;
  2. @EnableAutoConfiguration中使用了 @Import({AutoConfigurationImportSelector.class})向容器中添加了一些组件(自动配置类):
  • 扫描所有jar包类路径下 META‐INF/spring.factories,把扫描到的这些文件的内容包装成properties对象,从properties中获取到 EnableAutoConfiguration.class类(类名)对应的值,然后把他们添加在容器中,即将类路径下 META-INF/spring.factories 里面配置的所有EnableAutoConfiguration的值加入到了容器中。
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration
  1. 每一个这样的xxxAutoConfiguration类都是容器中的一个组件,都加入到容器中,用他们来做自动配置。

盗用网上的一副图,感觉画的挺好的,就是有点大,建议大家在电脑上看:

mybatis-spring-boot-starter、spring-boot-starter-web等组件的META-INF文件下均含有spring.factories文件,自动配置模块中,SpringFactoriesLoader收集到文件中的类全名并返回一个类全名的数组,返回的类全名通过反射被实例化,就形成了具体的工厂实例,工厂实例来生成组件具体需要的bean。

原理分析

以HttpEncodingAutoConfiguration为例,就是以前在web.xml中配置的CharacterEncodingFilter过滤器:

//表示这是一个配置类,相当于以前编写的Spring配置文件
@Configuration
//启用HttpProperties类的ConfigurationProperties功能,通过配置文件为属性注入值,并将其添加到容器中
@EnableConfigurationProperties({HttpProperties.class})
//当该应用是web应用时才生效
@ConditionalOnWebApplication(type 
= Type.SERVLET)
//必须包含CharacterEncodingFilter类才生效
@ConditionalOnClass({CharacterEncodingFilter.class})
//如果配置文件中有spring.http.encoding选项则该配置生效,否则不生效。但是默认已经生效了
@ConditionalOnProperty(prefix 
"spring.http.encoding",value = {"enabled"},matchIfMissing = true)
public class HttpEncodingAutoConfiguration {
    private final Encoding properties;
    //将容器中的HttpProperties注入
    public HttpEncodingAutoConfiguration(HttpProperties properties) {
        this.properties = properties.getEncoding();
    }
    //将返回的filter添加到容器中,作为bean
    @Bean
    //如果容器中没有这个bean才会生效
    @ConditionalOnMissingBean
    public CharacterEncodingFilter characterEncodingFilter() {
        CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
        filter.setEncoding(this.properties.getCharset().name());
        filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST));
        filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE));
        return filter;
    }
}
//从配置文件中获取指定的值,然后绑定到指定的属性值
@ConfigurationProperties(
    prefix = "spring.http"
)
public class HttpProperties {
    private Charset charset;
    private Boolean force;
    private Boolean forceRequest;
    private Boolean forceResponse;
    private Map<Locale, Charset> mapping;
}

注意:

  • 根据当前情况进行判断,决定配置类是否生产,如果不满足条件自动配置就不会生效
  • 自动配置类xxAutoConfiguration的属性是从对应的xxProperties类中获取
  • xxProperties类中的信息是通过配置文件注入绑定的,可以通过配置文件指定属性的值

自动配置类必须在一定的条件下才能生效,我们怎么知道哪些自动配置类生效,我们可以通过启用debug=true属性,来让控制台打印自动配置报告,这样我们就可以很方便的知道哪些自动配置类生效:

=========================
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)
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)

简单总结一下:

  • SpringBoot在启动时会加载大量的自动配置类
  • 通过自动配置了向容器中添加组件
  • 通过这些组件自动完成许多功能,从而简化配置

SpringBoot全流程总结

为了让大家形成知识闭环,我将之前的SpringBoot执行流程整体,通过几幅图再整体串一下:

什么?图片字体太小,看不清楚?那我放大一下。

构建SpringApplication:

启动SpringApplication:

自动化配置加载:

如果还是看不清楚,就在电脑上看吧,楼哥也没办法。

上图为SpringBoot启动结构图:

  • 构建SpringApplication:进行SpringApplication的初始化模块,配置一些基本的环境变量、资源、构造器、监听器
  • 启动SpringApplication:实现了应用具体的启动方案,包括启动流程的监听模块、加载配置环境模块、及核心的创建上下文环境模块
  • 自动化配置加载:是自动化配置模块,该模块作为springboot自动配置核心,在后面的分析中会详细讨论。

前面知识的更多细节,请参考《【Spring Boot系列1】一文带你了解Spring Boot(上)》、《【Spring Boot系列1】一文带你了解Spring Boot(下)》两文。

后记

上面需要总结的知识,基本都已经总结过了,这里就写点水文吧。

今天6月20日父亲节,先祝天下所有的父亲--父亲节快乐!其它俏皮的话,我就不说了。

对于Java的学习,目前已经完成Java并发编程、Spring、SpringBoot、MyBatis的学习(相关系列文章可到我的公众号自取),几个主流的框架和核心技术,也算是初步学习了一遍,耗时42天。后面还有Maven、Dubbo、SpringCloud和SpringMVC,感觉学习来应该更快,这些更多是微服务框架,相关知识我可能只需要了解个大概,知道基本的使用就行,预计2周左右定。

后面打算花些时间,仔细研读《JAVA编程思想》和《深入理解Java虚拟机》这两本书,开启Java学习的第二个阶段--进阶阶段!到时也给自己列个详细的Plan,当然,如果中途计划有变,再做调整。

预计7月初,完成Java初阶知识的学习,到时也写一篇总结文章,会涵盖这段时间所学的所有Java知识,也帮助Java小白形成自己的知识体系。

欢迎大家多多点赞,更多文章,请关注微信公众号“楼仔进阶之路”,点关注,不迷路~~

楼仔

2021/07/18  阅读:68  主题:橙心

作者介绍

楼仔