如何自定义spring boot starter项目
问题
Spring Boot 通过很多 starter 依赖,提供很多常用组件的默认配置,大大地简化开发时,集成第三方组件时所需的配置;
我们如何实现一个自定义的 starter 项目,以便简化我们开发时引入内部相关组件所需的配置。
方案
自定义 starter 的步骤如下:
- 创建项目
- 引入必要依赖
- 自定义 Properties 类
- 定义核心服务类
- 定义自动配置类
- 打包发布
- 创建用于测试 starter 的项目
1.创建项目
命名规范:
- Spring 官方的 starter 通常被命名为 spring-boot-starter-(名字) ,如 “spring-boot-starter-web” 。
- Spring 官方建议非官方的 starter 命名遵循 “(名字)-spring-boot-starter” 的格式,如"myxxx-spring-boot-starter" 。
可参考《如何快速构建一个Spring Boot项目》。
项目坐标
<groupId>com.chen.solution.starter</groupId>
<artifactId>demo-spring-boot-starter</artifactId>
<version>1.0.0</version>
2.引入必要依赖
自定义的 starter 是不能有启动入口的,即它只能作为工具类。所以,不要把自定义的 pom.xml 写成一个可启动的项目。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
- :假如 Project A 的某个依赖 D 添加了true,当其它项目通过pom依赖Project A的时候,D不会被传递依赖进来。
3.自定义 Properties 类
在使用 starter 时,可以在 application.properties 文件中配置参数,以覆盖默认值。
在自定义 starter 时,可以根据需要来配置 Properties 类,以保存配置信息,例:
@ConfigurationProperties(
prefix = "spring.chen.starter"
)
@Getter
@Setter
public class StarterProps {
private String word = "default";
}
4.定义核心服务类
每个 starter 都需要有自己的功能,所以需要定义服务类。
public class MyStarter {
private StarterProps starterProps;
public MyStarter(){
}
public MyStarter(StarterProps starterProps){
this.starterProps = starterProps;
}
public String hello(){
String msg = "hello:"+ starterProps.getWord();
System.out.println(msg);
return msg;
}
}
5.定义自动配置类
每个 starter 一般至少有一个自动配置类,命名规则为 “名字+AutoConfiguration”。
@Configuration
@EnableConfigurationProperties(StarterProps.class)
// 在类路径 classpath 下有指定的类的情况下进行自动配置
@ConditionalOnClass(MyStarter.class)
// 属性 matchIfMissing=true 时进行自动配置
@ConditionalOnProperty(prefix="spring.chen.starter",value="enabled",matchIfMissing = true)
public class StarterServiceAutoConfiguration {
@Resource
private StarterProps starterProps;
@Bean
// 在容器中没有指定 Bean 的情况下自动配置 MyStarter 类
@ConditionalOnMissingBean(MyStarter.class)
public MyStarter myStarter(){
MyStarter myStarter = new MyStarter(starterProps);
return myStarter;
}
}
在 resources 文件夹下新建目录 META-INF ,在目录中新建 spring.factories 文件,并且在 spring.factories 中配置 AutoConfiguration ,如下所示:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.chen.solution.starter.demo.config.StarterServiceAutoConfiguration
多个类,使用逗号隔开,例:
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.web.WebMvcAutoConfiguration,\
...
6.打包发布
打成 Jar 包,发布到本地私有仓库或 Maven 私有仓库中。
使用命令 mvn clean install 发布到本地仓库。
使用 mvn clean deploy 发布到私有仓库。
7.创建用于测试 starter 的项目
创建测试项目,引入自定义的 starter 项目依赖:
<dependency>
<groupId>com.chen.solution.starter</groupId>
<artifactId>demo-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
指定配置参数
# 自定义 starter 配置
spring.chen.starter.word=world
执行测试用例,使用 starter
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoSpringBootStarterTestApplicationTests {
@Resource
private MyStarter myStarter;
@Test
public void contextLoads() {
myStarter.hello();
}
}
常用注解说明
-
注解
@EnableConfigurationProperties
:让使用了@ConfigurationProperties
注解的类生效,并且将该类注入到 IOC 容器中,交由 IoC 容器进行管理 。 -
注解
@ConditionalOnClass
:是 Spring Boot 实现自动配置的重要支撑之一。其用途是判断当前 classpath 下是否存在指定类,若是则将当前的配置装载入Spring IoC 容器。 -
注解
@ConditionalOnProperty
:在 Spring Boot 中有时候需要控制配置类是否生效,可以使用@ConditionalOnProperty
注解来控制@Configuration
是否生效。属性 matchIfMissing=true 时进行自动配置 。- name和value不能同时存在.也不能同时不存在, 两者只能存在一个。
- 如果havingValue存在, 则跟havingValue的值进行比较, 相同返回true, 不同则返回false
- 如果没有指定havingValue, 则用prefix + name 或者prefix + value获取配置项的值, 然后跟 "false"字符串比较, 相同返回false, 不同返回true
- 相同: 即配置项值为false时, 例spring.chen.starter.enabled=false, 此时是不加载被修饰的类或方法。
- 不同: 即配置项值为非false的任何值, 例spring.chen.starter.enabled=true / spring.chen.starter.enabled=123 / spring.chen.starter.enabled= 等, 都是返回true. 此时加载被修饰的类或方法。
- 在配置matchIfMissing后, 如果prefix + name 或者prefix + value 都不存在, 则以matchIfMissing的值为准.
- matchIfMissing = true, 则加载
- matchIfMissing = false, 则不加载
-
注解
@ConditionalOnMissingBean
:根据当前环境或者容器情况来动态注入bean,要配合@Bean使用@ConditionalOnMissingBean
Spring 容器中不存在该类型Bean时起效;作用:判断当前需要注入 Spring 容器中的bean的实现类是否已经含有,有的话不注入,没有就注入。@ConditionalOnBean
Spring 容器中存在该类型Bean时起效;作用:判断当前需要注册的bean的实现类否被 Spring 管理,如果被管理则注入,反之不注入。
-
注解
@Conditional
:作用:Spring4 推出了@Conditional
注解,方便程序根据当前环境或者容器情况来动态注入bean,按照一定的条件进行判断,满足条件给容器注册bean。
代码仓库
https://gitee.com/chentian114/solution-springboot