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 包含以下组件:
- 一个 autoconfigure 模块,包含了自动注入的代码。
- 一个 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. 参考资料
- https://docs.spring.io/spring-boot/docs/2.2.2.RELEASE/reference/html/using-spring-boot.html#using-boot-starter
- https://docs.spring.io/spring-boot/docs/2.2.2.RELEASE/reference/html/spring-boot-features.html#boot-features-custom-starter
- https://www.baeldung.com/spring-boot-custom-starter
- https://github.com/eugenp/tutorials/tree/master/spring-boot-custom-starter
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于