主要讲解SpringBoot自动化配置原理,结合系列1的内容,可以形成SpringBoot原理知识体系闭环。
SpringBoot只是个框架,前期我主要了解该框架内部的执行原理,然后掌握SpringBoot的基本使用姿势,就达到我的初步目标,后面打算结合公司具体的项目,然后再慢慢学习。
一般认为,SpringBoot 微框架从两个主要层面影响 Spring 社区的开发者们:
我理解,一个就是去XML配置,一个就是自动化配置。
SpringBoot 提供的这些“开箱即用”的依赖模块都约定以 spring-boot-starter- 作为命名的前缀,常用的如下:
并且皆位于 org.springframework.boot 包或者命名空间下(虽然 SpringBoot 的官方参考文档中提到不建议大家使用 spring-boot-starter- 来命名自己写的类似的自动配置依赖模块,但实际上,配合不同的 groupId,这不应该是什么问题)。
那么自动化配置,在SpringBoot的执行流程中处于哪个环节呢?它又是怎么自动化加载配置的呢?其实我们在之前的文章中,就可以找到部分答案。
在文章《【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等等,我把他们理解为“扩展功能”,感觉更贴切一些,支持“自动加载”和“开箱即用”。
# 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
盗用网上的一副图,感觉画的挺好的,就是有点大,建议大家在电脑上看:
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;
}
注意:
自动配置类必须在一定的条件下才能生效,我们怎么知道哪些自动配置类生效,我们可以通过启用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执行流程整体,通过几幅图再整体串一下:
什么?图片字体太小,看不清楚?那我放大一下。
构建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小白形成自己的知识体系。
欢迎大家多多点赞,更多文章,请关注微信公众号“楼仔进阶之路”,点关注,不迷路~~