Spring Boot自动配置

本文主要介绍spring boot的神器之一,自动配置,主要从以下几个方面介绍自动配置:

  1. 先决条件Starter
  2. spring.factories机制
  3. Enable系列注解
  4. 自动配置原理
  5. 自动配置实例分析
  6. 创建自己的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结构上来看,可以看出几点:

  1. starter的作用主要是模块化依赖,一站式解决单独依赖问题。因为starter中并没有任何java code。
  2. starter中有个spring.providers文件,该文件主要是为了提供给STS或者一些IDE检测识别需要的依赖,并没有实际具体作用
  3. 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扫描解析,无非就以下几种形式:

  1. 通过制定scan package形式,让spring扫描
  2. 通过类似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的形式展示

以上的这些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实现如下:

  1. 判断是否开启自动配置,如果未开启,则直接返回空的String[]
  2. 使用SpringFacotriesLoader从类路径上的META-INF/spring.factories中载入所有的org.springframework.boot.autoconfigure.EnableAutoConfiguration
  3. 移除重复的Configuration
  4. 排序Configuration
  5. 返回这些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从而传递依赖相应的自动配置。自动配置分为两类:

  1. spring boot内置
  2. 非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。

posted @ 2020-03-17 17:06  怀瑾握瑜XI  阅读(2007)  评论(0编辑  收藏  举报