Springboot 系列(三)Spring Boot 自动配置
注意:本 spring boot 系列文章基于 spring boot 版本 v2.1.1.release 进行学习分析,版本不同可能会有细微差别。
前言
关于配置文件可以配置的内容,在 spring boot 官方网站已经提供了完整了配置示例和解释。
可以这么说,spring boot 的一大精髓就是自动配置,为开发省去了大量的配置时间,可以更快的融入业务逻辑的开发,那么自动配置是怎么实现的呢?
1. @springbootapplication
跟着 spring boot 的启动类的注解 @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 {
@enableautoconfiguration
开启自动配置。
@componentscan
开启注解扫描
从 springbootapplication
我们可以发现,这是一个简便的注解配置,它包含了自动配置,配置类,包扫描等一系列功能。
2. @enableautoconfiguration
继续跟踪,查看@enableautoconfiguration
源码,里面比较重要的是 @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 {}; }
继续跟踪 autoconfigurationimportselector.class
.在这个类有一个重要的方法 getcandidateconfigurations
.用于加载 spring boot 配置的自动配置类。
getautoconfigurationentry
会筛选出有效的自动配置类。
protected autoconfigurationentry getautoconfigurationentry( autoconfigurationmetadata autoconfigurationmetadata, annotationmetadata annotationmetadata) { if (!isenabled(annotationmetadata)) { return empty_entry; } annotationattributes attributes = getattributes(annotationmetadata); list<string> configurations = getcandidateconfigurations(annotationmetadata, attributes); configurations = removeduplicates(configurations); set<string> exclusions = getexclusions(annotationmetadata, attributes); checkexcludedclasses(configurations, exclusions); configurations.removeall(exclusions); configurations = filter(configurations, autoconfigurationmetadata); fireautoconfigurationimportevents(configurations, exclusions); return new autoconfigurationentry(configurations, exclusions); } protected list<string> getcandidateconfigurations(annotationmetadata metadata, annotationattributes attributes) { list<string> configurations = springfactoriesloader.loadfactorynames( getspringfactoriesloaderfactoryclass(), getbeanclassloader()); assert.notempty(configurations, "no auto configuration classes found in meta-inf/spring.factories. if you " + "are using a custom packaging, make sure that file is correct."); return configurations; }
下图是 debug 模式下筛选之后的结果,因为我只添加了 web 模块,所以只有 web 相关的自动配置。
3. xxxautoconfiguration 与 xxxproperties
在上面的 debug 里,我们看到了成功加载的自动配置,目前只看到了配置类,却还没有发现自动配置值,随便选择一个 autoconfiguration
查看源码。
这里选择了 servletwebserverfactoryautoconfiguration
.
@configuration @autoconfigureorder(ordered.highest_precedence) //判断当前项目有没有这个类 //characterencodingfilter;springmvc中进行乱码解决的过滤器; @conditionalonclass(servletrequest.class) //spring底层@conditional注解(spring注解版),根据不同的条件,如果 //满足指定的条件,整个配置类里面的配置就会生效; 判断当前应用是否是web应用,如果是,当前配置类生效 @conditionalonwebapplication(type = type.servlet) @enableconfigurationproperties(serverproperties.class) @import({ servletwebserverfactoryautoconfiguration.beanpostprocessorsregistrar.class, servletwebserverfactoryconfiguration.embeddedtomcat.class, servletwebserverfactoryconfiguration.embeddedjetty.class, servletwebserverfactoryconfiguration.embeddedundertow.class }) public class servletwebserverfactoryautoconfiguration {
需要注意的是 @enableconfigurationproperties(serverproperties.class)
.他的意思是启动指定类的configurationproperties
功能;将配置文件中对应的值和 serverproperties
绑定起来;并把serverproperties
加入到 ioc 容器中。
再来看一下 serverproperties
.
@configurationproperties(prefix = "server", ignoreunknownfields = true) public class serverproperties { /** * server http port. */ private integer port;
显而易见了,这里使用 configurationproperties 绑定属性映射文件中的 server 开头的属性。结合默认配置
# 路径spring-boot-autoconfigure-2.1.1.release.jar # /meta-inf/spring-configuration-metadata.json { "name": "server.port", "type": "java.lang.integer", "description": "server http port.", "sourcetype": "org.springframework.boot.autoconfigure.web.serverproperties", "defaultvalue": 8080 }
达到了自动配置的目的。
4. 自动配置总结
- springboot 启动的时候加载主配置类,开启了自动配置功能 @enableautoconfiguration 。
- @enableautoconfiguration 给容器导入meta-inf/spring.factories 里定义的自动配置类。
- 筛选有效的自动配置类。
- 每一个自动配置类结合对应的 xxxproperties.java 读取配置文件进行自动配置功能 。
5. 配置类
通过自动配置,我们发现已经帮我们省去了大量的配置文件的编写,那么在自定义配置的时候,我们是不是需要编写xml呢?spring boot 尽管可以使用 springapplication
xml 文件进行配置,但是我们通常会使用 @configuration
类进行代替,这也是官方推荐的方式。
5.1 xml配置
定义 helloservice bean.
<?xml version="1.0" encoding="utf-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="helloservice" class="net.codingme.boot.service.helloservice"></bean> </beans>
引入配置。
@importresource(value = "classpath:spring-service.xml") @springbootapplication public class bootapplication { public static void main(string[] args) { springapplication.run(bootapplication.class, args); } }
5.2 注解配置
此种方式和上面的xml配置是等效的,也是官方推荐的方式。@configuration
注解的类(要在扫描的包路径中)会被扫描到。
/** * <p> * 配置类,相当于传统spring 开发中的 xml-> bean的配置 * * @author niujinpeng * @date 2018/12/7 0:04 */ @configuration public class serviceconfig { /** * 默认添加到容器中的 id 为方法名(helloservice) * * @return */ @bean public helloservice helloservice() { return new helloservice(); } }
6. 附录
@conditional扩展注解 | 作用(判断是否满足当前指定条件) |
---|---|
@conditionalonjava | 系统的java版本是否符合要求 |
@conditionalonbean | 容器中存在指定bean; |
@conditionalonmissingbean | 容器中不存在指定bean; |
@conditionalonexpression | 满足spel表达式指定 |
@conditionalonclass | 系统中有指定的类 |
@conditionalonmissingclass | 系统中没有指定的类 |
@conditionalonsinglecandidate | 容器中只有一个指定的bean,或者这个bean是首选bean |
@conditionalonproperty | 系统中指定的属性是否有指定的值 |
@conditionalonresource | 类路径下是否存在指定资源文件 |
@conditionalonwebapplication | 当前是web环境 |
@conditionalonnotwebapplication | 当前不是web环境 |
@conditionalonjndi | jndi存在指定项 |
文章代码已经上传到 github spring boot 自动配置。
<完>
本文原发于个人博客: 转载请注明出处
上一篇: Java基础系列-Comparable和Comparator
下一篇: 记录我的十年创业心路历程
推荐阅读
-
Spring Boot入门系列八(SpringBoot 整合Mybatis)
-
spring-boot-2.0.3不一样系列之源码篇 - run方法(三)之createApplicationContext,绝对有值得你看的地方
-
Spring Boot2 系列教程 (二) | 第一个 SpringBoot 工程详解
-
SpringBoot 源码解析 (三)----- Spring Boot 精髓:启动时初始化数据
-
SpringBoot系列:Spring Boot集成定时任务Quartz
-
Spring Boot 2.x 教程系列 | 配置 Undertow 容器
-
springboot系列(三)配置文件详解
-
JAVA SpringBoot 项目打成jar包供第三方引用自动配置(Spring发现)解决方案
-
Springboot 系列(三)Spring Boot 自动配置
-
spring-boot-2.0.3不一样系列之番外篇 - springboot事件机制,绝对有值得你看的地方