Creating a Custom Starter with Spring Boot – 用Spring Boot创建一个自定义启动器

最后修改: 2017年 4月 19日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

The core Spring Boot developers provide starters for most of the popular open source projects, but we are not limited to these.

核心的Spring Boot开发人员为大多数流行的开源项目提供starters,但我们并不局限于这些。

We can also write our own custom starters. If we have an internal library for use within our organization, it would be a good practice to also write a starter for it if it’s going to be used in Spring Boot context.

我们也可以编写自己的自定义启动器。如果我们有一个内部库供组织内部使用,那么如果要在Spring Boot上下文中使用,为它写一个启动器也是一个好的做法。

These starters enable developers to avoid lengthy configuration and quickly jumpstart their development. However, with a lot of things happening in the background, it sometimes becomes difficult to understand how an annotation or just including a dependency in the pom.xml enables so many features.

这些启动器使开发人员能够避免冗长的配置,并快速启动他们的开发。然而,由于后台发生了很多事情,有时很难理解一个注释或只是在pom.xml中包含一个依赖关系是如何实现这么多功能的。

In this article, we’ll demystify the Spring Boot magic to see what’s going on behind the scenes. Then we will use these concepts to create a starter for our own custom library.

在这篇文章中,我们将揭开Spring Boot的神秘面纱,看看幕后发生了什么。然后我们将使用这些概念为我们自己的自定义库创建一个启动器。

2. Demystifying Spring Boot’s Autoconfiguration

2.解密Spring Boot的自动配置

2.1. Auto Configuration Classes

2.1.自动配置类

When Spring Boot starts up, it looks for a file named spring.factories in the classpath. This file is located in the META-INF directory. Let’s look at a snippet of this file from the spring-boot-autoconfigure project:

当Spring Boot启动时,它会在classpath中寻找一个名为spring. factories的文件。这个文件位于META-INF目录中。让我们看看这个文件的一个片段,它来自 spring-boot-autoconfigure项目。

# 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

This file maps a name to different configuration classes which Spring Boot will try to run. So, as per this snippet, Spring Boot will try to run all the configuration classes for RabbitMQ, Cassandra, MongoDB and Hibernate.

该文件将一个名称映射到Spring Boot将尝试运行的不同配置类。因此,根据这个片段,Spring Boot 将尝试运行 RabbitMQ、Cassandra、MongoDB 和 Hibernate 的所有配置类。

Whether or not these classes will actually run will depend on the presence of dependent classes on the classpath. For example, if the classes for MongoDB are found on the classpath, MongoAutoConfiguration will run and all the mongo related beans will be initialized.

这些类是否会实际运行,将取决于classpath上是否存在依赖性类。例如,如果在classpath上找到MongoDB的类,MongoAutoConfiguration将运行,所有与mongo相关的bean将被初始化。

This conditional initialization is enabled by the @ConditionalOnClass annotation. Let’s look at the code snippet from MongoAutoConfiguration class to see its usage:

这种条件性初始化是由@ConditionalOnClass注解启用的。让我们看一下MongoAutoConfiguration类的代码片段,看看它的用法。

@Configuration
@ConditionalOnClass(MongoClient.class)
@EnableConfigurationProperties(MongoProperties.class)
@ConditionalOnMissingBean(type = "org.springframework.data.mongodb.MongoDbFactory")
public class MongoAutoConfiguration {
    // configuration code
}

Now how – if the MongoClient is available in the classpath – this configuration class will run populating the Spring bean factory with a MongoClient initialized with default config settings.

现在如何–如果MongoClient在classpath中可用–这个配置类将运行填充Spring Bean工厂的MongoClient,用默认配置设置进行初始化。

2.2. Custom Properties from the application.properties File

2.2.来自application.properties文件的自定义属性

Spring Boot initializes the beans using some pre-configured defaults. To override those defaults, we generally declare them in the application.properties file with some specific name. These properties are automatically picked up by the Spring Boot container.

Spring Boot使用一些预先配置的默认值来初始化Bean。要覆盖这些默认值,我们一般会在application.properties文件中用一些特定的名称声明它们。这些属性会被Spring Boot容器自动接收。

Let’s see how that works.

让我们看看效果如何。

In the code snippet for MongoAutoConfiguration, @EnableConfigurationProperties annotation is declared with the MongoProperties class which acts as the container for custom properties:

MongoAutoConfiguration的代码片段中,@EnableConfigurationProperties 注解与MongoProperties类一起被声明,该类作为自定义属性的容器。

@ConfigurationProperties(prefix = "spring.data.mongodb")
public class MongoProperties {

    private String host;

    // other fields with standard getters and setters
}

The prefix plus the field name make the names of the properties in the application.properties file. So, to set the host for MongoDB, we only need to write the following in the property file:

前缀加上字段名构成application.properties文件中的属性名称。因此,要为MongoDB设置host,我们只需要在属性文件中写下以下内容。

spring.data.mongodb.host = localhost

Similarly, values for other fields in the class can be set using the property file.

同样地,类中其他字段的值也可以用属性文件来设置。

3. Creating a Custom Starter

3.创建一个自定义启动器

Based on the concepts in section 2, to create a custom starter we need to write the following components:

基于第2节的概念,要创建一个自定义的启动器,我们需要编写以下组件。

  1. An auto-configure class for our library along with a properties class for custom configuration.
  2. A starter pom to bring in the dependencies of the library and the autoconfigure project.

For demonstration, we have created a simple greeting library that will take in a greeting message for different times of day as configuration parameters and output the greeting message. We will also create a sample Spring Boot application to demonstrate the usage of our autoconfigure and starter modules.

为了进行演示,我们创建了一个简单的问候语库,它将接收一天中不同时间的问候语作为配置参数并输出问候语。我们还将创建一个Spring Boot示例应用程序,以演示我们的自动配置和启动器模块的用法。

3.1. The Autoconfigure Module

3.1.自动配置模块

We’ll call our auto configure module greeter-spring-boot-autoconfigure. This module will have two main classes i.e. GreeterProperties which will enable setting custom properties through application.properties file and GreeterAutoConfiguartion which will create the beans for greeter library.

我们将把我们的自动配置模块称为greeter-spring-boot-autoconfigure。这个模块将有两个主要的类,即GreeterPropertiesGreeterAutoConfiguartion,前者将通过application.properties文件设置自定义属性,后者将为greeter库创建bean。

Let’s look at the code for both the classes:

让我们看看这两个班的代码。

@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

}
@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);
    }
}

We also need to add a spring.factories file in the src/main/resources/META-INF directory with the following content:

我们还需要在src/main/resources/META-INF目录下添加一个spring. factories文件,内容如下。

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.baeldung.greeter.autoconfigure.GreeterAutoConfiguration

On application startup, the GreeterAutoConfiguration class will run if the class Greeter is present in the classpath. If run successfully, it will populate the Spring application context with GreeterConfig and Greeter beans by reading the properties via GreeterProperties class.

在应用程序启动时,如果classpath中存在Greeter类,那么GreeterAutoConfiguration类将运行。如果运行成功,它将通过GreeterConfigGreeterBean,通过GreeterProperties类读取属性来填充Spring应用上下文。

The @ConditionalOnMissingBean annotation will ensure that these beans will only be created if they don’t already exist. This enables developers to completely override the auto-configured beans by defining their own in one of the @Configuration classes.

@ConditionalOnMissingBean注解将确保只有在这些Bean不存在时才会被创建。这使得开发者能够通过在@Configuration类中定义自己的Bean来完全覆盖自动配置的Bean。

3.2. Creating pom.xml

3.2.创建pom.xml

Now let’s create the starter pom which will bring in the dependencies for the auto-configure module and the greeter library.

现在,让我们创建一个初始pom,它将带来自动配置模块和greeter库的依赖。

As per the naming convention, all the starters which are not managed by the core Spring Boot team should start with the library name followed by the suffix -spring-boot-starter. So we will call our starter as greeter-spring-boot-starter:

根据命名惯例,所有不由Spring Boot核心团队管理的启动器都应该以库名开头,后面加上后缀-spring-boot-starter。因此,我们将把我们的启动器称为greeter-spring-boot-starter:

<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. Using the Starter

3.3.使用启动器

Let’s create greeter-spring-boot-sample-app which will use the starter. In the pom.xml we need to add it as a dependency:

让我们创建greeter-spring-boot-sample-app,它将使用这个启动器。在pom.xml中,我们需要把它作为一个依赖项加入。

<dependency>
    <groupId>com.baeldung</groupId>
    <artifactId>greeter-spring-boot-starter</artifactId>
    <version>${greeter-starter.version}</version>
</dependency>

Spring Boot will automatically configure everything and we will have a Greeter bean ready to be injected and used.

Spring Boot将自动配置一切,我们将有一个Greeterbean准备好被注入和使用。

Let’s also change some of the default values of the GreeterProperties by defining them in the application.properties file with the baeldung.greeter prefix:

让我们也改变一些GreeterProperties的默认值,在application.properties文件中用baeldung.greeter前缀定义它们。

baeldung.greeter.userName=Baeldung
baeldung.greeter.afternoonMessage=Woha\ Afternoon

Finally, let’s use the Greeter bean in our application:

最后,让我们在我们的应用程序中使用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);
    }
}

4. Conclusion

4.结论

In this quick tutorial, we focused on rolling out a custom Spring Boot starter, and on how these starters, together with the autoconfigure mechanism – work in the background to eliminate a lot of manual configuration.

在这个快速教程中,我们重点介绍了推出一个自定义的Spring Boot启动器,以及这些启动器与自动配置机制一起如何在后台工作,以消除大量的手动配置。

The complete source code for all the modules we created in this article can be found over on GitHub.

我们在本文中创建的所有模块的完整源代码可以在GitHub上找到