# 定制标准Spring_Boot_starter

back:springBoot

starter

我们每次构建一个 Spring 应用程序时,我们都不希望从头开始实现具有「横切关注点」的内容;相反,我们希望一次性实现这些功能,并根据需要将它们包含到任何我们要构建的应用程序中。在Spring Boot中,用于表示提供这种横切关注点的模块的术语是 starter,通过依赖 starter 可以轻松使用其包含的一些功能特性,无论你的工作中是否会构建自己的 starter,你都要具有构建 「starter」的思想

通常一个完整的 starter 需要包含下面两个组件:

# Auto Configure Module

back

通过这种方式,我们可以构建可以自动贡献于应用程序上下文的模块,以及添加某个特性或提供对某个外部库的访问

# Starter Module

back

Spring Boot Starter 是一个 Maven 或 Gradle 模块,其唯一目的是提供 "启动" 某个特性所需的所有依赖项。可以包含一个或多个 Auto-Configure Module (自动配置模块)的依赖项,以及可能需要的任何其他依赖项。这样,在Spring 启动应用程序中,我们只需要添加这个 starter 依赖就可以使用其特性

# 命名

back

来自 Spring 官方的 starter 都是 以 spring-boot-starter 开头,比如:

  • spring-boot-starter-web
  • spring-boot-starter-aop

如果我们自定义 starter 功能名称叫acme,那么我们的命名是这样的:

  • acme-spring-boot-starter
  • acme-spring-boot-autoconfigure

如果 starter 中用到了配置 keys,也要注意不要使用 Spring Boot 使用的命名空间,比如(server,management,spring)

# Parent Module创建

back

一级目录结构:

.
├── pom.xml
├── rgyb-spring-boot-autoconfigure
├── rgyb-spring-boot-sample
└── rgyb-spring-boot-starter
1
2
3
4
5

二级目录结构:

.
├── pom.xml
├── rgyb-spring-boot-autoconfigure
│   ├── pom.xml
│   └── src
├── rgyb-spring-boot-sample
│   ├── pom.xml
│   └── src
└── rgyb-spring-boot-starter
    ├── pom.xml
    └── src
1
2
3
4
5
6
7
8
9
10
11

创建一个空的父亲 Maven Module,主要提供依赖管理,这样 SubModule 不用单独维护依赖版本号,来看 pom.xml 内容:

<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>

    <!--  添加其他全局依赖管理到这里,submodule默认不引入这些依赖,需要显式的指定  -->
</dependencyManagement>
1
2
3
4
5
6
7
8
9
10
11
12
13

# Auto Configure Module构建

back

新建类 GreetingAutoConfiguration

@Configuration
public class GreetingAutoConfiguration {

    @Bean
    public GreetingService greetingService(GreetingProperties greetingProperties){
        return new GreetingService(greetingProperties.getMembers());
    }
}
1
2
3
4
5
6
7
8
@AllArgsConstructor
public class GreetingService {
    private List<String> members = new ArrayList<>();
    public void sayHello(){
        members.forEach(s -> System.out.println("hello " + s));
    }
}
1
2
3
4
5
6
7

resources 目录下新建文件 META-INF/spring.factories (如果目录 META-INF 不存在需要手工创建),向文件写入内容:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
 top.dayarch.autoconfigure.GreetingAutoConfiguration
1
2

Spring 启动时会在其 classpath 中所有的 spring.factoreis文件,并加载里面的声明配置,GreetingAutoConfiguration 类就绪后,我们的 Spring Boot Starter 就有了一个自动激活的入口点

# 条件配置

back

为类添加两个条件注解:

@Configuration
@ConditionalOnProperty(value = "rgyb.greeting.enable", havingValue = "true")
@ConditionalOnClass(DummyEmail.class)
public class GreetingAutoConfiguration {
    ...
}
1
2
3
4
5
6
  • 通过使用 @ConditionalOnProperty 注解,我们告诉 Spring,只有属性 rgyb.greeting.enable值被设置为 true 时,才将 GreetingAutoConfiguration (以及它声明的所有 bean ) 包含到应用程序上下文中
  • 通过使用 @ConditionalOnClass 注解,我们告诉Spring 只有类 DummyEmail.class 存在于 classpath 时,才将 GreetingAutoConfiguration (以及它声明的所有 bean ) 包含到应用程序上下文中

# 配置属性管理

back

上面使用了 @ConditionalOnProperty 注解,实际 starter 中可能有非常多的属性,所以我们需要将这些属性集中管理:

@Data
@ConfigurationProperties(prefix = "rgyb.greeting")
public class GreetingProperties {

    /**
     * GreetingProperties 开关
     */
    boolean enable = false;

    /**
     * 需要打招呼的成员列表
     */
    List<String> members = new ArrayList<>();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

我们知道这些属性是要在 application.yml 中使用的,当我们需要使用这些属性时,为了让 IDE 给出更友好的提示,我们需要在 pom.xml 中添加依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>
1
2
3
4
5

# 提升启动时间

back

对于类路径上的每个自动配置类,Spring Boot 必须计算 @Conditional… 条件值,用于决定是否加载自动配置及其所需的所有类,根据 Spring 启动应用程序中 starter 的大小和数量,这可能是一个非常昂贵的操作,并且会影响启动时间,为了提升启动时间,我们需要在 pom.xml 中添加另外一个依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-autoconfigure-processor</artifactId>
    <optional>true</optional>
</dependency>
1
2
3
4
5

这个注解会生成一个名为 spring-autoconfigure-metadata.properties Property 文件

# Starter Module构建

back

Starter Module 的构建很简单了,你可以认为它就是一个空 module,除了依赖 Auto-Configure Module,其唯一作用就是为了使用 starter 功能特性提供所有必须依赖,所以我们为 starter module 的 pom.xml 文件添加如下内容:

<dependencies>
    <dependency>
        <groupId>top.dayarch.learnings</groupId>
        <artifactId>rgyb-spring-boot-autoconfigure</artifactId>
        <version>1.0.0.RELEASE</version>
    </dependency>

    <!-- 在此处添加其他必要依赖,保证starter可用 -->
</dependencies>
1
2
3
4
5
6
7
8
9

同样在 resources 目录下新建文件 META-INF/spring.providers , 其内容如下:

providers: rgyb-spring-boot-autoconfigure
1

该文件主要作用是说明 starter module 的依赖信息,多个依赖以逗号分隔就好,该文件不会影响 starter 的使用,可有可无

# 创建Sample Module

back

参考mybatis-plus