0. 写在前面
这部分内容将会简要介绍如何定制自己的starter,以及starter的一些基本原理
1. starter的pom文件配置
starter本身也是作为一个spring boot的应用,因此需要引入parent,同时引入基本的starter
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
为了给可配置的bean属性生成元数据,我们需要引入如下jar包
<!--将被@ConfigurationProperties注解的类的属性注入到元数据-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
生成的元数据位于jar文件中的META-INF/spring-configurationmetadata. json
。元数据本身并不会修改被@ConfigurationProperties
修饰的类属性,在我的理解里元数据仅仅只是表示配置类的默认值以及java doc,供调用者便利的了解默认配置有哪些以及默认配置的含义,在idea里面如果有元数据则可以提供良好的代码提示功能以方便了解默认的配置。
自定义的starter的配置类如下:
@ConfigurationProperties(prefix = QssProperties.PROP_PREFIX)
public class QssProperties {
public static final String PROP_PREFIX = "qss";
/**
* qss en name
*/
private String name;
private Integer age = 27;
@NestedConfigurationProperty
private BasicProperties basicProperties;
public String getName() {
return name;
}
public QssProperties setName(String name) {
this.name = name;
return this;
}
public Integer getAge() {
return age;
}
public QssProperties setAge(Integer age) {
this.age = age;
return this;
}
public BasicProperties getBasicProperties() {
return basicProperties;
}
public QssProperties setBasicProperties(BasicProperties basicProperties) {
this.basicProperties = basicProperties;
return this;
}
}
public class BasicProperties {
private String basic;
public String getBasic() {
return basic;
}
public BasicProperties setBasic(String basic) {
this.basic = basic;
return this;
}
}
生成的元数据配置如下:
{
"hints": [],
"groups": [
{
"sourceType": "com.qss.autoconfigure.QssProperties",
"name": "qss",
"type": "com.qss.autoconfigure.QssProperties"
},
{
"sourceType": "com.qss.autoconfigure.QssProperties",
"name": "qss.basic-properties",
"sourceMethod": "getBasicProperties()",
"type": "com.qss.autoconfigure.BasicProperties"
}
],
"properties": [
{
"sourceType": "com.qss.autoconfigure.QssProperties",
"defaultValue": 27,
"name": "qss.age",
"type": "java.lang.Integer"
},
{
"sourceType": "com.qss.autoconfigure.BasicProperties",
"name": "qss.basic-properties.basic",
"type": "java.lang.String"
},
{
"sourceType": "com.qss.autoconfigure.QssProperties",
"name": "qss.name",
"description": "qss en name",
"type": "java.lang.String"
}
]
}
group表示元数据的分组,properties表示属性列表,sourceType表示来源类,type表示属性的类型,name表示属性名,defaultValue表示默认值,sourceMethod表示贡献该组属性的方法名,比如这里的getBasicProperties()
来获取basicProperties
的配置。这里需要注意的是在basicProperties
上使用了@NestedConfigurationProperty,该注解会为basicProperties
生成单独的一个属性组。如果不添加该注解,则不会生成单独的属性组,而是形成如下的一个属性节点:
{
"sourceType": "com.qss.autoconfigure.QssProperties",
"name": "qss.basic-properties",
"type": "com.qss.autoconfigure.BasicProperties"
},
2. starter的入口
Spring Boot会检查你发布的jar中是否存在 META-INF/spring.factories
文件,
该文件中以 EnableAutoConfiguration 为key的属性应该列出你的配置类
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.mycorp.libx.autoconfigure.LibXAutoConfiguration,\
com.mycorp.libx.autoconfigure.LibXWebAutoConfiguration
我们可以使用 @AutoConfigureAfter
或@AutoConfigureBefore
或者@Order
注解为配置类指定特定的顺序,在demo中我使用的配置是:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.qss.autoconfigure.QssStarterConfig
配置类的定义如下,首先需要使用@Configuration
,通过@EnableConfigurationProperties
可以将被@ConfigurationProperties
注解的类生成一个bean。再来看QssService
这个bean的配置,我们可以通过一系列@Condition*
注解来表示bean的生成条件,这里使用了@ConditionalOnClass({QssService.class}),@ConditionalOnMissingBean({QssService.class})
表示生成这个bean需要保证类路径下QssProperties.class
这个类并且该bean不存在于spring的上下文。注意@ConditionalOnBean
并不保证bean的加载顺序,spring boot只是通过扫描判断是否会生成该bean
@Configuration
@EnableConfigurationProperties({QssProperties.class})
public class QssStarterConfig {
@Autowired
private QssProperties qssProperties;
@Bean
@ConditionalOnClass({QssService.class})
@ConditionalOnMissingBean({QssService.class})
public QssService getQssService(){
return new QssService().setProperties(qssProperties);
}
}
一些其他的条件注解如下:
@ConditionalOnWebApplication : web环境
@ConditionalOnNotWebApplication : 条件是当前不是web应用
@ConditionalOnProperty : 检查特定属性是否已经配置了特定值
@ConditionalOnResource : 检查特定的资源是否已经在类路径下
@ConditionalOnMissingClass : 不包含某个类
@ConditionalOnSingleCandidate: 表示只能有一个候选bean,如果超过一个,可以使用@Primary指定首选,这样才不会抛出异常
3. bean类的编写
这里只使用了一个简单的bean,当其他项目引入该starter时,qssService
这个bean已经可以直接依赖注入到项目中其他类。
public class QssService {
private QssProperties properties;
public QssService setProperties(QssProperties properties) {
this.properties = properties;
return this;
}
public String sayHello(){
return JSON.toJSONString(properties);
}
}
作者:ImushroomT
链接:https://www.jianshu.com/p/547fe62365f8
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
自定义spring boot starter
最新推荐文章于 2024-08-16 16:03:09 发布