创建自定义的Spring Boot Starter
1. 概述
Spring boot的开发人员给那些流行的开源项目提供了很多Starter,但是我们并不局限于这些。
我们可以创建自己的Starter,如果我们有一个公司内部使用的代码库,如果我们实在Spring boot 项目中使用,那给这个代码库创建一个Spring boot Starter是一个很好的实践。
这些自定义的Starter可以帮助开发人员避免繁冗复杂的配置代码,以便快速的开始代码开发,通过自定义Starter,这些配置工作将自动完成。
2.Spring Boot自动配置介绍
2.1. 自动配置类
当一个Spring Boot应用启动的时候,它将会在类路径下查找命名为spring.factories文件,这个文件被定义在META-INF目录下。
下面是spring-boot-autoconfigure项目下的spring.factories文件部分内容
spring.factories
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
这个文件定义了一些映射类,Spring boot应用在启动时将会尝试去运行这些配置类。就上面的代码而言,Spring boot将会运行RabbitAutoConfiguration、CassandraAutoConfiguration、MongoAutoConfiguration、HibernateJpaAutoConfiguration这几个配置类,这些配置类是否实际运行要根据类路径中是否有所需要的依赖而定。例如,MongoDB所需依赖包在类路径中被找到,那么MongoAutoConfiguration配置类将会被运行,去进行一些mongodb相关的自动配置和bean初始化工作。
MongoAutoConfiguration
@Configuration
@ConditionalOnClass(MongoClient.class)
@EnableConfigurationProperties(MongoProperties.class)
@ConditionalOnMissingBean(type = "org.springframework.data.mongodb.MongoDbFactory")
public class MongoAutoConfiguration {
// configuration code
}
Spring boot通过@ConditionalOnClass来判断配置类会不会被执行。从上面的代码可以看到如果类路径中存在MongoClient类,并且SpringBoot容器中不存在org.springframework.data.mongodb.MongoDbFactory的bean,那么MongoAutoConfiguration配置类将会被运行。
2.2. 在application.properties文件中自定义配置属性值
在MongoAutoConfiguration配置类中,可以看到有一个@EnableConfigurationProperties(MongoProperties.class)注解,这个注解表明Spring Boot会将application.properties配置的特定的属性收集到MongoProperties类中。
MongoProperties
@ConfigurationProperties(prefix = "spring.data.mongodb")
public class MongoProperties {
private String host;
// other fields with standard getters and setters
}
@ConfigurationProperties(prefix = "spring.data.mongodb")注解表明Spring boot将会收集spring.data.mongodb开头的配置到MongoPropertie类中。
application.properties
spring.data.mongodb.host = localhost
localhost将会被设置到MongoProperties的host属性上。
3. 创建自定义Starter
根据Spring Boot官方文档所介绍的,创建一个自定义的Starter通常需要两个模块(当然也不是必须的,对于配置相对简单的项目只需一个模块是更合适的)。同时官方文档也表明自定义的Spring Boot Starter命名方式为suffix-spring-boot-starter。
- 一个autoconfigure模块包含自动配置类以及properties相关类和配置。
- 一个starter模块,包含autoconfigure所需依赖,以及使用自定义Starter所需的所有代码和类库代码依赖等。
下面我们通过一个例子说明如何创建一个自定义的Starter。
3.1. Autoconfigure类
我们将自定义的autoconfigure模块命名为greeter-spring-boot-autoconfigure,这个模块将包含两个类,GreeterProperties类用来收集在application.properties 中配置的自定义properties属性;GreeterAutoConfiguartion类用来初始化配置和声明Bean。
GreeterProperties
@ConfigurationProperties(prefix = "baeldung.greeter")
public class GreeterProperties {
private String userName;
private String morningMessage;
private String afternoonMessage;
private String eveningMessage;
private String nightMessage;
// standard getters and setters
}
GreeterAutoConfiguration
@Configuration
@ConditionalOnClass(Greeter.class)
@EnableConfigurationProperties(GreeterProperties.class)
public class GreeterAutoConfiguration {
@Autowired
private GreeterProperties greeterProperties;
@Bean
@ConditionalOnMissingBean
public GreetingConfig greeterConfig() {
String userName = greeterProperties.getUserName() == null
? System.getProperty("user.name")
: greeterProperties.getUserName();
// ..
GreetingConfig greetingConfig = new GreetingConfig();
greetingConfig.put(USER_NAME, userName);
// ...
return greetingConfig;
}
@Bean
@ConditionalOnMissingBean
public Greeter greeter(GreetingConfig greetingConfig) {
return new Greeter(greetingConfig);
}
}
定义了上面这些并不能使Springboot运行这些配置类,接下来我们还需要在src/main/resources/META-INF下定义一个spring.factories文件
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.baeldung.greeter.autoconfigure.GreeterAutoConfiguration
通过上面三个步骤,Spring Boot应用在启动时将会查找类路径下是否存在Greeter类。如果存在,那么GreeterAutoConfiguration配置类将会被Spring Boot类运行。同时将会读取application.properties中读取baeldung.greeter开头的配置,填充到GreeterProperties类的属性中。
为什么创建Bean的方法中要使用@ConditionalOnMissingBean注解呢,因为通过这个注解我们自定义的Starter向用户提供了覆盖自动配置的能力,用户可以通过自己声明GreetingConfig和Greeter bean来按需配置。
3.2. 创建Starter模块的pom.xml
<project ...>
<modelVersion>4.0.0</modelVersion>
<groupId>com.baeldung</groupId>
<artifactId>greeter-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<greeter.version>0.0.1-SNAPSHOT</greeter.version>
<spring-boot.version>2.2.6.RELEASE</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>com.baeldung</groupId>
<artifactId>greeter-spring-boot-autoconfigure</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.baeldung</groupId>
<artifactId>greeter</artifactId>
<version>${greeter.version}</version>
</dependency>
</dependencies>
</project>
3.3. 使用自定义Starter
在自己应用的pom.xml文件中引入Starter依赖
<dependency>
<groupId>com.baeldung</groupId>
<artifactId>greeter-spring-boot-starter</artifactId>
<version>${greeter-starter.version}</version>
</dependency>
在application.properties中定义配置
baeldung.greeter.userName=Baeldung
baeldung.greeter.afternoonMessage=Woha\ Afternoon
在应用中使用Greeter Bean
@SpringBootApplication
public class GreeterSampleApplication implements CommandLineRunner {
@Autowired
private Greeter greeter;
public static void main(String[] args) {
SpringApplication.run(GreeterSampleApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
String message = greeter.greet();
System.out.println(message);
}
}
注:如果spring.factories中映射的是org.springframework.boot.autoconfigure.EnableAutoConfiguration=...,则Spring Boot将会自动加载并运行映射的配置类。除此之外也可以使用自定义的映射,此时需要自己实现配置类加载代码。详情参考。