【从零开始学Spring Boot】-17.Spring Boot Starter自定义


1.简介

1.1 概述

A typical Spring Boot starter contains code to auto-configure and customize the infrastructure of a given technology, let’s call that “acme”. To make it easily extensible, a number of configuration keys in a dedicated namespace can be exposed to the environment. Finally, a single “starter” dependency is provided to help users get started as easily as possible.

典型的Spring Boot Starter包含用于自动配置和自定义特定技术的基础架构的代码,我们称其为“ acme”。为了使其易于扩展,可以将专用命名空间中的许多配置项公开给环境。最后,提供了一个 starter 依赖项,以帮助用户尽可能轻松地使用它。

1.2 特点

Concretely, a custom starter can contain the following:

  • The autoconfigure module that contains the auto-configuration code for “acme”.
  • The starter module that provides a dependency to the autoconfigure module as well as “acme” and any additional dependencies that are typically useful. In a nutshell, adding the starter should provide everything needed to start using that library.

This separation in two modules is in no way necessary. If “acme” has several flavours, options or optional features, then it is better to separate the auto-configuration as you can clearly express the fact some features are optional. Besides, you have the ability to craft a starter that provides an opinion about those optional dependencies. At the same time, others can rely only on the autoconfigure module and craft their own starter with different opinions.

If the auto-configuration is relatively straightforward and does not have optional feature, merging the two modules in the starter is definitely an option.

具体而言,自定义启动器可以包含以下内容:

  • 自动配置模块,其中包含“ acme”的自动配置代码。
  • 启动程序模块,它提供对自动配置模块的依赖以及“ acme”和通常有用的任何其他依赖。简而言之,添加启动程序应提供开始使用该库所需的一切。

完全没有必要将这两个模块分开。如果“ acme”具有多种功能,选项或可选功能,则最好将自动配置分开,因为您可以清楚地表示某些功能是可选的。此外,您还可以制作一个启动器,以提供有关那些可选依赖项的意见。同时,其他人只能依靠自动配置模块并以不同的意见来制作自己的启动器。如果自动配置相对简单并且不具有可选功能,则将两个模块合并在启动器中绝对是一种选择。

2.演示环境

  1. JDK 1.8.0_201
  2. Spring Boot 2.2.0.RELEASE
  3. 构建工具(apache maven 3.6.3)
  4. 开发工具(IntelliJ IDEA )

3.演示代码

3.1 代码说明

包含两个项目,两个项目的作用如下:

  • demo-spring-boot-starter:自定义的starter,有一个Hello接口和几个实现类,通过自动装配类从外部获取配置来选择具体要激活的实例,同时helloTemplate的模板工具类来调用Hello中的hello方法。
  • test-spring-boot-starter:依赖 demo-spring-boot-starter,测试它的功能

3.2 代码结构

demo-spring-boot-starter

test-spring-boot-starter

3.3 maven 依赖

demo-spring-boot-starter

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

test-spring-boot-starter

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>com.soulballad.usage</groupId>
        <artifactId>demo-spring-boot-starter</artifactId>
        <version>${project.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

3.4 配置文件

demo-spring-boot-starter

META-INF\spring.factories

# 配置自动装配
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.soulballad.usage.springboot.autoconfiguration.HelloAutoConfiguration

test-spring-boot-starter

application.properties

com.soulballad.hello.java.enable=true
com.soulballad.hello.detail.name=zhangsan
com.soulballad.hello.detail.age=20

3.5 java代码

demo-spring-boot-starter

Hello.java

public interface Hello {

    String hello();
}

HelloGirl.java

public class HelloGirl implements Hello {
    @Override
    public String hello() {
        return "hello girl";
    }
}

HelloJava.java

public class HelloJava implements Hello{
    @Override
    public String hello() {
        return "hello java";
    }
}

HelloWorld.java

public class HelloWorld implements Hello{
    @Override
    public String hello() {
        return "hello world";
    }
}

HelloProperties.java

@Component
@ConfigurationProperties(prefix = HelloProperties.HELLO_PREFIX)
public class HelloProperties {

    public static final String HELLO_PREFIX = "com.soulballad.hello";

    private Map<String, Object> detail;

    public Map<String, Object> getDetail() {
        return detail;
    }

    public void setDetail(Map<String, Object> detail) {
        this.detail = detail;
    }
}

HelloAutoConfiguration.java

@Configuration
@EnableConfigurationProperties(HelloProperties.class)
public class HelloAutoConfiguration {

    @Bean
    public HelloTemplate helloTemplate(Hello hello, HelloProperties helloProperties) {
        return new HelloTemplate(hello, helloProperties);
    }

    @Bean
    @Primary
    @ConditionalOnProperty(prefix = HelloProperties.HELLO_PREFIX + ".world", name = "enable", havingValue = "true")
    public Hello helloWorld() {
        return new HelloWorld();
    }

    @Bean
    @ConditionalOnProperty(prefix = HelloProperties.HELLO_PREFIX + ".java", name = "enable", havingValue = "true")
    public Hello helloJava() {
        return new HelloJava();
    }

    @Bean
    @ConditionalOnProperty(prefix = HelloProperties.HELLO_PREFIX + ".girl", name = "enable", havingValue = "true")
    public Hello helloGirl() {
        return new HelloGirl();
    }
}

HelloTemplate.java

public class HelloTemplate {

    private Hello hello;
    private HelloProperties helloProperties;

    public HelloTemplate(Hello hello, HelloProperties helloProperties) {
        this.hello = hello;
        this.helloProperties = helloProperties;
    }

    public String hello() {
        Map<String, Object> objectMap = helloProperties.getDetail();
        String helloName = hello.getClass().getSimpleName();
        String description = "helloName: " + helloName + ", properties: " + objectMap.toString();
        return hello.hello() + ", " + description;
    }
}

test-spring-boot-starter

HelloController.java

@RestController
public class HelloController {

    @Autowired
    private HelloTemplate helloTemplate;

    @GetMapping(value = "/hello")
    public String hello() {
        return helloTemplate.hello();
    }
}

3.6 git 地址

spring-boot/spring-boot-11-custom-starter

4.效果展示

使用maven将 demo-spring-boot-starter 打成 jar 包,然后在 test-spring-boot-starter 中依赖这个 jar包

启动 test-spring-boot-starter 中 TestSpringBootStarterApplication.main 方法,在 test-spring-boot-starter.http 访问下列地址,观察输出信息是否符合预期。

### GET /hello
GET http://localhost:8080/hello

5.参考

  1. Spring Boot Features/Starter

文章作者: Soulballad
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Soulballad !
评论
 上一篇
【源码分析-Spring Boot】-16.Spring Boot Starter 加载和解析 【源码分析-Spring Boot】-16.Spring Boot Starter 加载和解析
Spring Boot Starter:【从零开始学Spring Boot】-17.Spring Boot Starter自定义 1.自定义 starter 原理分析demo-spring-boot-starter 中 Hello 接口
2020-08-02
下一篇 
【源码分析-Spring Boot】-15.Spring Boot MessageConverter 执行和原理 【源码分析-Spring Boot】-15.Spring Boot MessageConverter 执行和原理
Spring Boot MessageConverter:【从零开始学Spring Boot】-16.Spring Boot MessageConverter消息转 1.自定义MessageConverter执行流程以 UserCont
2020-07-30
  目录