创建自定义的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将会自动加载并运行映射的配置类。除此之外也可以使用自定义的映射,此时需要自己实现配置类加载代码。详情参考。

参考链接

示例完整代码

posted @ 2023-06-24 15:22  我爱这世间美貌女子  阅读(117)  评论(0编辑  收藏  举报