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
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于