编写自己的Spring-Boot的starter
- 【概念理解】starter是一种服务——使得使用某个功能的开发者不需要关注各种依赖库的处理,不需要具体的配置信息, 由Spring Boot自动通过classpath路径下的类发现需要的Bean,并织入相应的Bean。举个栗子,spring-boot-starter-jdbc这个starter的存在, 使得我们只需要在BookPubApplication下用@Autowired引入DataSource的bean就可以,Spring Boot会自动创建DataSource的实例。(记住啦,是一个服务,service, starter is a service)
- 【关于配置的好习惯】
@ConfigurationProperties注解的类会被spring-boot-configuration-processor检测,spring-boot-configuration-processor 的作用是编译时生成spring-configuration-metadata.json, 此文件主要给IDE使用,用于提示使用。如在intellij idea中,当配置此jar相关配置属性在application.yml, 你可以用ctlr+鼠标左键,IDE会跳转到你配置此属性的类中。这个是附加功能,对starter的用户友好。我为人人,人人为我。 - 【关于命名】这里说下artifactId的命名问题,Spring 官方 Starter通常命名为spring-boot-starter-{name} 如 spring-boot-starter-web。Spring官方建议非官方Starter命名应遵循{name}-spring-boot-starter的格式。
- 【要素】
- 编写service类实现,
- 编写ServiceProperties,要用@ConfigurationProperties注解声明一下,这样Spring就会根据注解读取application.yml的配置,根据配置创建这个ServiceProperties的Bean实例。
- 编写AutoConfigure,用于控制Bean的初始化创建工作(这个类似编写application-context.xml, 但是他比application多一个功能,那就是可以通过@Conditional这些条件注解,进行控制是否开启。因为Spring-Boot强调的是约定优先,事先约定条件,进行默认配置。不要动不动就得重新配置)
- 在resources/META-INF/创建spring.factories文件,文件内容如下,由于SpringBoot启动的时候不会扫描AutoConfigure类(Bean创建用的上下文),而是扫描所有Jar包的【resources/META-INF/】目录,然后才会加载AutoConfigure类,并初始化Service实例。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.xncoding.starter.config.ExampleAutoConfigure
完整代码如下:
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
</dependencies>
// 编写服务类
public class ExampleService {
private String prefix;
private String suffix;
public ExampleService(String prefix, String suffix) {
this.prefix = prefix;
this.suffix = suffix;
}
public String wrap(String word) {
return prefix + word + suffix;
}}
// 编写配置模板类
@ConfigurationProperties("example.service")
public class ExampleServiceProperties {
private String prefix;
private String suffix;
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public String getSuffix() {
return suffix;
}
public void setSuffix(String suffix) {
this.suffix = suffix;
}
}
// 编写Spring上下文类
@Configuration@ConditionalOnClass(ExampleService.class)@EnableConfigurationProperties(ExampleServiceProperties.class)public class ExampleAutoConfigure {
private final ExampleServiceProperties properties;
@Autowired
public ExampleAutoConfigure(ExampleServiceProperties properties) {
this.properties = properties;
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "example.service", value = "enabled",havingValue = "true")
ExampleService exampleService (){
return new ExampleService(properties.getPrefix(),properties.getSuffix());
}
}
// 添加meta文件到resources/META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.xncoding.starter.config.ExampleAutoConfigure
// mvn:install 打包安装
// 测试过程
// 引入starter
<dependency>
<groupId>com.xncoding</groupId>
<artifactId>simple-spring-boot-starter</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
// 编写 application.yml 配置
example.service:
enabled: true
prefix: ppp
suffix: sss
// main方法
@RunWith(SpringRunner.class)@SpringBootTestpublic class ApplicationTests {
@Autowired
private ExampleService exampleService;
@Test
public void testStarter() {
System.out.println(exampleService.wrap("hello"));
}
}
- 【关键知识点,必看】@ConditionalOnMissingBean配置注解的类,可以被重写(也就可以重新定义类的初始化,比如默认是单例的Bean可以改成多例,又或者默认的application.yml参数满足你的需求,你也可以重新搞一个)