如何实现一个 Spring Boot Starter

本贴最后更新于 1837 天前,其中的信息可能已经沧海桑田

1. Starter 是什么

在实现 Spring Boot Starter 之前,首先要明确实现 Spring Boot Starter 是干嘛用的?看一下官方的描述:

Starters are a set of convenient dependency descriptors that you can include in your application. You get a one-stop shop for all the Spring and related technologies that you need without having to hunt through sample code and copy-paste loads of dependency descriptors. For example, if you want to get started using Spring and JPA for database access, include the spring-boot-starter-data-jpa dependency in your project.

Starters 是一些便捷实用的依赖,可以在工程中引用。你可以通过 Starter,直接得到你所需要的 Spring 以及相关技术的一站式服务,而不再需要通过复制样例代码和依赖的方式。举个例子,如果你需要使用 Spring 和 JPA 来进行数据库访问,只需要在工程中引入 spring-boot-starter-data-jpa 依赖即可。

通过官方的描述,我们可以发现 Starter 是通过自动注入和依赖管理的方式来帮我们简化应用开发。

##2. Starter 构成

一个完整的 Spring Boot Starter 包含以下组件:

  1. 一个 autoconfigure 模块,包含了自动注入的代码。
  2. 一个 starter 模块,提供 autoconfigure 模块所需要的依赖。简而言之,这个 starter 需要包含启动该 starter 所需要的所有依赖。

以 github 上一个 spring-boot-custom-starter 库为例(见参考资料 4),我们看下一个 Starter 工程的样例:

$ tree -L 2
.
├── README.md
├── greeter
│   └── pom.xml
├── greeter-library
│   ├── README.md
│   ├── pom.xml
│   └── src
├── greeter-spring-boot-autoconfigure
│   ├── pom.xml
│   └── src
├── greeter-spring-boot-sample-app
│   ├── pom.xml
│   └── src
├── greeter-spring-boot-starter
│   └── pom.xml
└── pom.xml 

其中,greeter-library 是一个等待我们简化的组件,而 greeter-spring-boot-sample-app 是使用 greeter-library 的一个应用。greeter-spring-boot-autoconfigure 与 greeter-spring-boot-starter 是简化 greeter-library 所需要的 starter 组件。

我们可以看一下 greeter-spring-boot-sample-app 中 pom 文件的依赖部分:

<dependencies>
    <dependency>
        <groupId>com.baeldung</groupId>
        <artifactId>greeter-spring-boot-starter</artifactId>
        <version>${greeter-starter.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies> 

对应的代码:

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

跟我们实际开发中运用 starter 的方式是类似的。

那我们只需要分析一下 autoconfigure 与 starter 部分,就可以了解一个 stater 是如何构建的。

2.1 autoconfigure

这个子模块里只有两个 java 类与一个配置文件:

.
├── greeter-spring-boot-autoconfigure.iml
├── pom.xml
└── src/main
        ├── java
        │   └── com/baeldung/greeter/autoconfigure
        │                           ├── GreeterAutoConfiguration.java
        │                           └── GreeterProperties.java
        └── resources
            ├── META-INF
            │   └── spring.factories
            └── logback.xml 

我们看一下 spring.factories 中的配置:

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

这里申明了需要自动注入的配置,spring-boot 启动会后扫描该文件,执行自动注入的逻辑:

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

} 

对应的 GreeterProperties 这里就不贴了。

@ConditionalOnClass(Greeter.class)表示:当应用启动时,如果 Spring Boot 发现 Greeter 存在于 classpath 中,那么 GreeterAutoConfiguration 就会被执行。

当 GreeterAutoConfiguration 执行时,Spring 容器如果发现工程中没有定义 GreetingConfig 这个 Bean,则会默认通过 greeterConfig()方法创建一个,并放到 Spring 容器中。类似的,如果 pring 容器如果发现工程中没有定义 Greeter 这个 Bean,则会默认根据 greeter(...)方法创建一个,并放到 Spring 容器中。

@ConditionalOnMissingBean 表示如果容器中不存在对应的 Bean 才会去执行并创建对应的 Bean。所以,在应用可以通过 @Configuration 等方式自定义创建对应的 Bean,以替换默认实现。

2.2 starter

我们会看到 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>1.5.2.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> 

该 pom.xml 规定了 starter 的名称叫:greeter-spring-boot-starter,以及使用的 greeter 库与 spring-boot 相关依赖的版本。

这里需要注意的是,我们平时使用的是 spring-boot-starter-xxx,是因为我们使用的 starter 大部分是 spring-boot 官方提供的 starter。而在实际工程中内部创建的 starter,官方是不建议按照这种方式进行命名的,以便为后续 Spring Boot 官方支持提供可能性。所以这里的命名方式是 xxx-spring-boot-starter。

3. 参考资料

  1. https://docs.spring.io/spring-boot/docs/2.2.2.RELEASE/reference/html/using-spring-boot.html#using-boot-starter
  2. https://docs.spring.io/spring-boot/docs/2.2.2.RELEASE/reference/html/spring-boot-features.html#boot-features-custom-starter
  3. https://www.baeldung.com/spring-boot-custom-starter
  4. https://github.com/eugenp/tutorials/tree/master/spring-boot-custom-starter
  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    943 引用 • 1460 回帖 • 3 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...