如何实现一个Spring Boot Starter 有更新!

  |   0 评论   |   280 浏览

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



---------------------------
本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处,尊重他人劳动。
转载请注明:文章转载自 xiajl.cn

评论

发表评论