Spring Boot自动配置
本文主要介绍spring boot的神器之一,自动配置,主要从以下几个方面介绍自动配置:
- 先决条件Starter
- spring.factories机制
- Enable系列注解
- 自动配置原理
- 自动配置实例分析
- 创建自己的Starter和自动配置
一.先决条件Starter
spring boot自动配置(如,web自动配置、数据源自动配置、redis自动配置等等)能够起作用的很大前提是基于Starter的应用。往往只要引用进某个模块的Starter,spring boot就能自动配置。比如引进spring-boot-starter-web,只需要在yml或者properties中配置:
- server.port
- server.context
就能启动spring boot应用,快速完成web应用的开发。而非像传统web工程那样需要配置复杂的web项目描述符web.xml等。其中就是因为spring boot根据依赖的spring-boot-starter-web,然后进行web方面的自动配置,比如创建web容器,DispatcherServlet。
既然Starter如此重要,它到底是什么?
Starter是一组非常方便的依赖集合,简单点说就是maven pom,不过该pom中聚合了一个模块相关的依赖。应用不需要再单独依赖,只需要依赖Starter,就可以一站式解决所需的依赖,对于自定义的starter甚至更能解决自动配置的依赖。如web应用,需要单独依赖tomcat、jsp-servlet、spring-web、spring-webmvc,但是spring boot只需要依赖spring-boot-starter-web,就可以将这些单独依赖全部依赖进你的应用,机器方便的同时,也解决了版本冲突和兼容问题。
以spring-boot-starter-web为例,分析下它的结构:
从以上的starter结构上来看,可以看出几点:
- starter的作用主要是模块化依赖,一站式解决单独依赖问题。因为starter中并没有任何java code。
- starter中有个spring.providers文件,该文件主要是为了提供给STS或者一些IDE检测识别需要的依赖,并没有实际具体作用
- starter的一站式依赖的同时还生效自动配置,因为只要依赖starter,启动时就可以自动配置
pom.xml中依赖如下:
pom中依赖了spring-web、spring-webmvc、starter-tomcat。通过starter可以一站式解决maven依赖问题。
至于第三点通过starter生效自动配置,在读完自动配置原理后,实例分析时再进行详解。那时更能深刻而透彻的理解它。
二.spring.factories机制
前面讲的starter,是自动配置的依赖基石,那么spring.factories机制就是自动配置的扩展载入策略。
自动配置需要依赖大量spring java configuration,这些配置往往都放在spring-boot-autoconfigure模块中(一般不会单独依赖这个模块pom,而是通过依赖starter的方式,后面实例分析是详解)。
然而这些配置如何被spring扫描解析,无非就以下几种形式:
- 通过制定scan package形式,让spring扫描
- 通过类似Java SPI机制将其载入
显然第一种方式不适合,因为每个模块的自动配置package都不一样,若要让应用开发者配置scan pacakge,不仅需要开发者关注autoconfigure的机制,而且也与自动相违背。
第二种方式便可以做到对应用开发者的透明处理,扩展性极好。spring.factories机制就是类似于Java SPI,在类路径上有个spring.factories文件,其中存需要自动配置的Java Configure类,然后通过Spring Factory Loader将其载入,作为spring的configuration class。
首先看下spring-boot-autoconfigure模块中的spring.factories:
在自动配置模块中都有这个文件,用于动态加载configuration class。再来看下其中内容:
该文件中存了大量的配置类,提供给spring加载作为configuration class,进行解析注册相应的Bean,这样就完成了自动配置,从而避免应用开发者手动配置的不便。
比如:org.springframework.boot.autoconfigure.aop.AopAutoConfiguration完成了spring aop的自动配置,这个自动配置中主要配置了spring aop需要的配置,从而避免日常非spring boot应用配置apo时,需要配置的一些基础apo配置(aop:aspectj-autoproxy,或者@EnableAspectJAutoProxy)。
通过以上的了解,更进一步理解自动配置,其实就是将以前非spring boot应用需要配置的大量Bean或者其他的基础配置(路径扫描、aop基础配置,或者数据源Bean)等等应用需要的基础配置迁移至已经固有的autoconfigure模块中,将其固化,从而减少甚至避免应用开发者再去进行手动配置,以提高应用开发的便捷。应用开发者只需要将所需的自动配置模块依赖进来,然后由spring自身进行自动化配置,这里有点控制反转的味道。
spring boot中由SpringFactoriesLoader这个类负责加载spring factories。下面分析下其原理:
SpringFactoriesLoader中有spring.factories的加载路径,固定在类路径下META-INF/spring.factories,其提供了以下几种形式加载spring configration class
- loadFactories,从META-INF/spring.factories中载入并实例化所给的类型
- loadFactoryNames,根据被给类型的名称从从META-INF/spring.factories中载入所给类的全限定名
其中具体载入细节,这里不再赘述,感兴趣读者可以阅读源码。主要是利用spring resource实现。
三.自动配置的关键注解系列
这节主要介绍开启自动配置和辅助自动配置的系列注解,以及它们每个的具体作用和用法。不过在具体介绍其之前,让我们先来看下spring中的另一套系列注解,这套系列注解和spring boot开启自动配置的注解同宗同源。
在spring中有一套Enable类型的注解,这套Enables注解都是用于开启spring应用某项功能,换而言之,就是将XML的配置形式以Java的形式展示
- @EnableAspectJAutoProxy,开启spring aop配置,类似于aop:aspectj-autoproxy
- @EnableAsync,开始异步配置,类似于task:*
- @EnableScheduling,开启定时配置,类似于task:*
- @EnableWebMvc,开启spring mvc,类似于mvc:annotation-driven
以上的这些Enable系注解都是告诉spring,让其配置基础Bean。让应该开发者更加关注业务,而无需深入的关注逐项配置,加速开发。
但是这些Enable系注解的作用原理是什么?
Enable系列注解开启spring某项功能的关键在于使用了@Import注解,每个@Enable注解的定义时都使用了@Import。
@Import注解的作用是将@Configuration、实现了ImportSelector或者ImportBeanDefinitionRegistrar接口的类、甚至规则的@Component的注解的注释类导入。这里关于Import类的原理过程在我的另一篇文章有详述,这里不再精讲。
@Enable注解通过@Import注解导入其特定功能的Bean,从而实现开启spring的特定功能。
spring boot的自动配置功能正是Enable系的另一个spring boot中的@EnableAutoConfiguration注解作用:
可以看粗@EnableAutoConfiguration也是通过@Import导入辅助Bean,从而开启spring boot的自动配置,下面就重点分析@EnableAutoConfiguration。
四.自动配置原理
@EnableAutoConfiguration中的@Import注解导入了EnableAutoConfigurationImportSelector,其实现了ImportSelector接口,spring的ConfigurationClassParser中在解析ConfigurationClass时会解析@Import注解,并执行ImportSelector的实现。下面重点分析EnableAutoConfigurationImportSelector的实现。
ImportSelector是spring提供导入Bean定义的扩展,需要导入配置时可以实现该接口:
其中selectImports方法返回被@Configuration注释的类的名字,spring将会载入这些配置类并解析注册Bean定义。
EnableAutoConfigurationImportSelector中的selectImports实现如下:
- 判断是否开启自动配置,如果未开启,则直接返回空的String[]
- 使用SpringFacotriesLoader从类路径上的META-INF/spring.factories中载入所有的org.springframework.boot.autoconfigure.EnableAutoConfiguration
- 移除重复的Configuration
- 排序Configuration
- 返回这些Configuration
这里需要重点关注的是META-INF/spring.factories中载入所有的org.springframework.boot.autoconfigure.EnableAutoConfiguration中的内容是什么。这里以spring-boot-autoconfigure中的部分内容为例介绍:
从以上可以看出,org.springframework.boot.autoconfigure.EnableAutoConfiguration项是配置类的列表,selectImports会返回这些列表,交给spring将这些配置类载入,然后解析注册成Bean Definition。由此,当@EnableAutoConfiguration开启后,spring-boot在启动时会载入类路径上的这些@Configuration的配置类,从而完成自动配置。
自动配置的原理用一段话总结下:
spring boot中预内置了大量配置类,其实就是将平时传统的spring应用的XML配置或者Java Config配置预先编排好,形成配置类放在spring-boot-autoconfigure项目中,当spring boot启动时就会载入这些预先编排的配置类。当然载入时还会根据各种条件决定是否载入,如@Conditional系注解就派上用场,其决定org.springframework.boot.autoconfigure.EnableAutoConfiguration中的哪些配置或者Bean定义被载入!
五.自动配置实例分析
本节将以自动配置实例来加深对自动配置原理的理解。这里对mybatis-spring-boot-autoconfigure分析:
首先看下spring.factories文件内容:
可见EnableAutoConfiguration项是mybatis的spring配置类,当spring boot启动时通过EnableAutoConfigurationImportSelector载入该配置类,解析注册成Bean定义。
众所周知,在日常项目开发中,使用mybatis和spring项目时,必须要配置的是SqlSessionFactory、SqlSessionTemplate这些mybatis的基础Bean,并且制定mapper的扫描目录等等属性。
再来分析下这个mybatis的配置类主要配置了哪些内容:
因为MybatisAutoConfiguration类被@Configuration注解修饰,所以是Spring的Java配置类,spring会解析该配置类中的@Bean修饰的方法,生成bean。从其中的配置可以看出,mybatis的关键注解SqlSessionFactory、SqlSessionTemplate都被注册成Bean。且使用了@Conditional系注解。当MapperFactoryBean不存在时,再使用@Import注解导入AutoConfiguredMapperScannerRegistrar,用于注册被@Mapper注解修饰的mybatis的mapper接口为代理bean:
从以上的mybatis-spring-boot-autoconfigure配置中更深入的学习了spring boot自动配置的原理,就是将以前传统的spring应用中需要开发者配编写的大量spring配置交给了spring boot自己配置,从而简化开发,简化项目,实现敏捷快速开发的一种有效方式。
其中还两个关键点需要注意的是:
@EnableConfigurationProperties注解也是Enable系注解之一,它是支持@ConfigurationProperties注解而生,它能够快速的注册被@ConfigurationProperties注释的类为spring bean。
一般项目不会直接引用自动配置工程,而是通过引用starter从而传递依赖相应的自动配置。自动配置分为两类:
- spring boot内置
- 非spring boot内置的(第三方开发、公司内部开发)
但是这些都是分为两个项目:starter和autoconfigure,如spring-boot-autoconfigure被spring-boot-starter依赖,mybatis-spring-boot-autoconfigure被mybatis-spring-boot-starter依赖。从而形成starter模块化,项目只需要依赖相应的starter便可以实现自动配置。
六.创建自己的Starter和自动配置
一般实现自动配置时,spring boot提出了规范。项目命名为 xxx-xxx-autoconfigure,其中目录结构为:
其中spring.factories是自动配置的配置类,其中配置了自动配置类、spring boot监听器类等等。
spring-configuration-metadata.json中配置了spring自动配置用到的属性以及属性的常用值,用于一些IDE在编写application.propertie或者application.yml时能够快捷的提示。
有了以上的原理和规范,实现自己需求的starter和自动配置就非常简单。这里可以实现netty-spring-boot-starter和netty-spring-boot-autoconfigure。