Spring Boot Starter 非权威指南
本篇内容算是对之前的Spring Boot自动装配装配原理做一个实践性的总结,结合在实际开发过程中对于Starter模块化的使用,算是给Spring Boot自动装配系列画上一个句号。
关于Spring Boot Starter想必大家都不陌生,在实际项目开发中,使用到Spring Boot应用或多或少都引入了一些应用功能相关所需求的Starter,譬如spring-boot-starter-web
,spring-boot-starter-data-jpa
等等。在Spring Boot官方文档的特性描述中就有如此一句:Provide opinionated 'starter' dependencies to simplify your build configuration
(提供启动依赖模块以简化构建项目的配置)。作为Spring Boot的宣传点stand-alone & production-grade
,starter是不可或缺的重要基石之一。
Starter模块开发
关于Starter的模块结构目前没有一个强制性的规定,可以使用单模块开发,也可以使用依赖包(即starter包 + autoconfiguration包)模式进行开发。我个人对于Starter的性质理解更像是一种插件,就像Spring官方在描述里所说的一样,目的是简化构建项目构建的配置,提升开发效率。所以Starter应该是模块化的,可拔插的,对于项目核心部分来说使用是无需关心内部逻辑的。目前生产应用中的Spring-boot项目从starter的角度来看是这样的。
单模块Starter
单模块Starter结构较为简单,一般不需要做额外的拆分,在模块的代码目录中创建一个@Configuration
类,在资源目录中创建META-INF/spring.factories
文件即可完成一个最简易starter的定义。为什么通过这两者能完成spring-starter的自动装配,其中的原理在之前的spring boot自动装配原理已经提到过,于此不再赘述。
DemoAutoConfiguration.java
1 |
|
spring.facoties
1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ |
在完成以上工作之后,在项目中进行starter的引用。
pom.xml
1 | <dependency> |
在主应用中使用starter内的功能。
1 |
|
1 | curl -X GET localhost:8080/test |
自此一个简单的单模块spring boot starter的开发到使用就已经结束。其中注册、自动装配的过程全部由Spring boot autoconfiguration完成了,我们只需要按照约定进行对于内容的开发即可,也符合Spring boot应用约定大于配置的基本原则。
依赖包Starter
依赖包Starter模式是目前第三方应用Starter所采用比较多的模式,和单模块Starter的区别在于使用者引入的starter包内只有pom
依赖,无实际代码,而pom
依赖中的autoconfiguration
才是starter的功能核心,负责相关@Bean
装配以及逻辑处理的过程。
以下是mybatis-spring-boot-starter
的依赖树,依赖结构算是第三方starter模块中比较经典的,大致的模块依赖结构如下。
1 | [INFO] --- maven-dependency-plugin:3.1.1:tree (default-cli) @ mybatis-spring-boot-starter --- |
从依赖树我们可以看出,mybatis-spring-boot-starter
依赖了spring-boot-starter
以保证引用目标对象持有最基础的spring-boot自动装配能力,而mybatis-spring-boot-autoconfigure
实现了mybatis
对于Spring-boot应用的支持(包括SqlSession
的装配、MapperScanner
的注册等等),mybatis-spring
实现了对spring的功能支持,mybatis
则负责了基础的能力实现。
依赖树的可读性不高,我们可以转换成图来看。
Starter的兄弟
@Conditional
关于@Conditional
注解的内容在Spring boot 自动装配原理中也有较为详尽的分析和描述,于此对原理方面的内容也就不打算过多深究了,感兴趣的朋友可以回看一下之前的内容。
在实际Starter模块开发过程中,经常会遇到starter所依赖的类、Spring Bean、配置不存在的情况,于此我们也就不再需要Spring自动装配功能对starter的配置进行解析处理。Spring也提供了以@Conditional
作为元注解的衍生注解以完成以上需求,由于衍生注解较多,于此用表格进行展示。
注解 | 描述 |
---|---|
@ConditionalOnProperty | 该注解用于对应用配置项进行检查,使用prefix 进行注解的前缀匹配,用havingVal 以检查配置项是否存在,用matchIfMissing 用于应对配置不存在采用默认值的情况 |
@ConditionalOnResource | 用于检查指向资源是否存在,若不存在则自动配置类不会被加载 |
@ConditionalOnClass /@ConditionalOnMissingClass | OnClass 和OnMissingClass 是相对的,用于检查classpath 下类是否存在或是否不存在,检查方式是通过asm 读取类元信息,而后通过classloader 对目标类进行加载,若加载成功则说明类存在,反之则不存在,具体逻辑在Spring boot自动装配系列中也有提到 |
@ConditionalOnBean /@ConditionalOnMissingBean | 与OnClass 类似,该注解用于检查Bean是否存在或不存在于Spring容器中 |
@ConditionalOnWebApplication /@ConditionalOnNotWebApplication | 用于检查当前应用类型是否为WEB应用(可细化到检查是否是Servlet应用或Reactive应用) |
@ConditionalOnExpression | 检查是否包含SpringEL的结果 |
其实基于@Conditional
注解的衍生还不止这些,@ConditionalOnJava
用于判断Jvm所运行的Java版本,@ConditionalOnJndi
用于检查目标资源是否存在等等,甚至说你也可以实现自己的@Conditional
衍生注解,只需要实现自己的Condition
类即可。
@ConfigurationProperties
在你为你的Starter定义了一套配置属性时,通过@Value
注解取值的效率往往太低了,此时不妨试一试@ConfigurationProperties
,让Spring将注解转换成你的Properties类,简化配置内容值的获取步骤,提高获取效率。注意,@ConfigurationProperties
和@Value
的功能是冲突的,当在@ConfigurationProperties
标注的类中使用@Value
,@Value
会进行值的覆盖。
小结
在实际开发过程中,对于泛用性较高的功能,譬如用户中心、数据查询分页、数据中台等等功能,都可以采用Starter的开发模式,以减少主应用的重复开发,同时也提高模块的复用率。Spring Cloud的系列微服务,在本质上也都是一个个的Starter插件,在进行少量的配置工作后提供强有力的功能。
当然在这里要小提一句,Spring官方不建议第三方的模块Starter命名以spring-boot-starter-xxx
进行,该命名方式通常适用于spring-boot的官方Starter
,在必要的情况下,官方会使用对你的自动装配特性进行支持。而建议的命名方式为xxx-spring-boot-starter
,如mybatis-spring-boot-starter
。
尾巴
最近对于自己的学习效率还是不太满意,之前许下的一个月两篇质量更新也已经连续两个月没有完成。对自己也有些稍许失望,但是在新的工作上也慢慢步入了正轨,希望…砥砺前行吧。以上,加油。