spring boot starter工程对于使用者是非常方便的,使用者通常只要在pom.xml引入starter的jar,则此工程依赖的类,就全部自动引入。因此我们常用的开源组件都会提供一个starter工程给开发者,让开发者非常方便集成本组件到spring中。本文通过自己实现一个简单的demo,详细说明了如何实现一个自己的spring boot starter工程。
本文demo参考mybatis-spring-boot-starter和网上的文章创建自己的start工程。
定义我们自己的spring boot starter工程,通常需要以下4个工程:
测试工程:
例子的功能说明:
此工程中不要引入扫描相关的注解,如@Autowire, @Componet, @Service, @Control等等; 不要引入spring 相关的类
本工程功能功能: 定义ITestService接口和此接口的两个实现类
定义ITestService接口
public interface ITestService {
String queryById(String id);
}
此接口的两个实现类
public class TestServiceImpl implements ITestService {
@Override
public String queryById(String id) {
return id + ":" + this.getClass().getSimpleName() ;
}
}
public class TestServiceBackImpl implements ITestService {
@Override
public String queryById(String id) {
return id + ":" + this.getClass().getSimpleName() ;
}
}
此工程中也不要引入扫描相关的注解,如@Autowire, @componet, @Service, @Controller等等
此类可以添加自己的类,这些类需要使用到spring-boot里的类。我们的例子里不需要添加和spring-boot相关的类,所有此工程没有java类。
这个工程主要定义子模块的需要用到的jar
定义版本信息和属性值,packaging值为pom
<artifactId>first-spring-boot</artifactId>
<groupId>com.hry.spring.first</groupId>
<version>1.0.0-SNAPSHOT</version>
<modelVersion>4.0.0</modelVersion>
<!-- 类型为pom -->
<packaging>pom</packaging>
<properties>
<first.version>1.0.0-SNAPSHOT</first.version>
<spring-boot.version>1.5.6.RELEASE</spring-boot.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
定义两个子模块
<modules>
<module>../first-spring-boot-autoconfigure</module>
<module>../first-spring-boot-starter</module>
</modules>
由于不是所有的子模块都会用到以下的类,所有使用dependencyManagement预先定义相关的jar和版本。保证在子类中需要使用时,只需要引入包,而不用使用版本号
<!-- 定义子模块中需要的jar -->
<dependencyManagement>
<dependencies>
<!-- spring boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- first model -->
<dependency>
<groupId>com.hry.spring.first</groupId>
<artifactId>first</artifactId>
<version>${first.version}</version>
</dependency>
<!-- first-spring-boot-autoconfigure -->
<dependency>
<groupId>com.hry.spring.first</groupId>
<artifactId>first-spring-boot-autoconfigure</artifactId>
<version>${first.version}</version>
</dependency>
<!-- first-spring-boot-starter -->
<dependency>
<groupId>com.hry.spring.first</groupId>
<artifactId>first-spring-boot-starter</artifactId>
<version>${first.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
配置自动扫描类
属性配置类,自动从配置文件中解析属性并生成对象
@ConfigurationProperties(prefix = FirstProperties.TEST_PREFIX)
public class FirstProperties {
public static final String TEST_PREFIX = "my.test";
private boolean openTestServiceBack; // 如果true,则创建openTestService,否则使用TestServiceBackImpl
private String name;
public boolean isOpenTestServiceBack() {
return openTestServiceBack;
}
public void setOpenTestServiceBack(boolean openTestServiceBack) {
this.openTestServiceBack = openTestServiceBack;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@EnableConfigurationProperties:启动上面的配置类
createTestService方法:根据配置的属性生成ITestService 的实现类
@Configuration
@EnableConfigurationProperties(FirstProperties.class)
public class FirstModuleAutoConfiguration {
@Autowired
private FirstProperties firstProperties;
@Bean
public ITestService createTestService(){
if(firstProperties.isOpenTestServiceBack()){
return new TestServiceBackImpl();
}else{
return new TestServiceImpl();
}
}
}
如果我们的FirstModuleAutoConfiguration 的初始化必须依赖其他的自动化配置类(如OtherModuleAutoConfiguration.class),则在此类上增加以下注解
@AutoConfigureAfter(OtherModuleAutoConfiguration.class)
我们还可以在配置类定义以下注解
另外我们也可以加上以下@Conditional条件注解
src/resources/META-INF/spring.factories:
配置FirstModuleAutoConfiguration在此文件,则spring boot会自动生成初始化此类
# Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=/ com.hry.spring.first.autoconfigure.FirstModuleAutoConfiguration
定义父类pom.xml
<parent>
<artifactId>first-spring-boot</artifactId>
<groupId>com.hry.spring.first</groupId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../first-spring-boot/pom.xml</relativePath>
</parent>
<artifactId>first-spring-boot-autoconfigure</artifactId>
<modelVersion>4.0.0</modelVersion>
引入相关的jar。其中 spring-boot-configuration-processor 的作用是编译时生成spring-configuration-metadata.json,此文件主要给IDE使用,用于提示使用。如在intellij idea中,当配置此jar相关配置属性在application.properties,你可以用ctlr+鼠标左键,IDE会跳转到你配置此属性的类中
<dependencies>
<!-- @ConfigurationProperties annotation processing (metadata for IDEs)
生成spring-configuration-metadata.json类,需要引入此类
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- first model -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
</dependency>
<dependency>
<groupId>com.hry.spring.first</groupId>
<artifactId>first</artifactId>
</dependency>
</dependencies>
starter工程,此工程没有java类,只在pom.xml中定义依赖的jar
此文件说明此工程依赖的模块,和pom.xml不同的地方这个文件主要给IDE使用,IDE会根据此文件提示使用者此模块的依赖jar。所以此文件就算什么都不配,对first模块使用也没有什么影响,最多IDE提示少一些。
英文说明:
It’s for tooling. STS (and other IDEs if they chose to) can index those files and make autocomplete suggestions based on stuff that isn’t yet on the classpath.’
spring.provides内容如下:
provides: spring-boot
引入父类和 定义artifactId
<parent>
<artifactId>first-spring-boot</artifactId>
<groupId>com.hry.spring.first</groupId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../first-spring-boot/pom.xml</relativePath>
</parent>
<artifactId>first-spring-boot-starter</artifactId>
依赖jar
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<!-- first-spring-boot-autoconfigure -->
<dependency>
<groupId>com.hry.spring.first</groupId>
<artifactId>first-spring-boot-autoconfigure</artifactId>
</dependency>
<!-- first module -->
<dependency>
<groupId>com.hry.spring.first</groupId>
<artifactId>first</artifactId>
</dependency>
</dependencies>
测试使用上面实现的starter工程
测试入口类:打印配置信息
@SpringBootApplication
public class TestApplication {
public static void main(String[] args){
ConfigurableApplicationContext cac = SpringApplication.run(TestApplication.class, args);
FirstProperties firstProperties = cac.getBean(FirstProperties.class);
System.out.println(firstProperties.getName());
ITestService testService = cac.getBean(ITestService.class);
System.out.println(testService.queryById("test"));
}
}
配置以下参数后,系统启动时,会自动生成FirstProperties对象,并注入以下值,然后FirstModuleAutoConfiguration根据open-test-service-back生成不同的ITestService的实现对象。
my:
test:
open-test-service-back: true
name: dsfdsd
引入刚刚生成first-spring-boot-starter工程
必须要引入snakeyaml-*.jar,否则系统无法识别yml格式的application.yml,从而使用我们的配置不起作用
<groupId>com.hry.spring.start</groupId>
<version>1.0-SNAPSHOT</version>
<modelVersion>4.0.0</modelVersion>
<artifactId>test-main</artifactId>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.hry.spring.first</groupId>
<artifactId>first-spring-boot-starter</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<!-- 如果要解析配置yml,则需要加入yml值 -->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.17</version>
</dependency>
</dependencies>
输出如下信息,则表示执行成功
dsfdsd test:TestServiceBackImpl
上文使用到的代码在github上,详细见 这里