一、Spring Boot自定义starter的原理
建议跳过第一部分,自己跟着步骤手写一个插件,再回头看这段解释就豁然开朗了 ????spring boot通过IO读取resources资源目录META-INF文件夹下的spring.factories文件,拿到类的全限定名,例如org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.david.learn.first.config.JsonConfiguration ,而JsonConfiguration 类名就是我们的配置类,将配置类中返回bean方法的业务逻辑类的实例交给spring ioc容器管理,这样就可以使用业务逻辑类的api方法去完成对第三方封装好的逻辑方法的调用。同时也支持接入starter的接入方定义配置参数,需要写Properties配置类,使用@ConfigurationProperties(prefix = "x.xx.xxx") 注解去定义参数的前缀,配置类的属性字段+前缀决定了用户定义的是哪个自定义参数,在配置类JsonConfiguration 中用@EnableConfigurationProperties(Properties.class) 使配置参数生效,同时注入配置参数字段,这样就可以获取(get)到接入方的自定义的参数。 ????其实这里用到了SPI(service provider interface)插件机制,一流产商定制接口,然后具体实现交给实现的厂商,就好比数据库的驱动类,上层定义了驱动接口,具体的驱动实现交给数据库厂商,比如mysql、oracle。类似于spring boot的自动装配,SPI机制是ServiceLoader读取META-INF/service目录下接口对应的文件,并读取里面的继承类名,然后通过类实例化到IOC容器中,最终我们就可以获取到了接口对应实现的子类。
二、手把手写一个Spring Boot自定义starter
????举个小需求的例子:提供一个starter,该starter完成对一个对象的格式化,例如传入一个对象,输出该对象的JSON表示,例如%对象的JSON文本% 。
2.1 编写业务处理类JsonConvertService
package com.david.learn.first.service;
import com.alibaba.fastjson.JSON;
public class JsonConvertService {
private String prefixName;
private String suffixName;
public String objectToJson(Object o) {
return prefixName + JSON.toJSONString(o) + suffixName;
}
public String getPrefixName() {
return prefixName;
}
public void setPrefixName(String prefixName) {
this.prefixName = prefixName;
}
public String getSuffixName() {
return suffixName;
}
public void setSuffixName(String suffixName) {
this.suffixName = suffixName;
}
}
2.2 编写自定义参数类JsonProperties
package com.david.learn.first.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "demo.json")
public class JsonProperties {
public static final String DEFAULT_PREFIX_NAME = "@";
public static final String DEFAULT_SUFFIX_NAME = "@";
private String prefixName = DEFAULT_PREFIX_NAME;
private String suffixName = DEFAULT_SUFFIX_NAME;
public String getPrefixName() {
return prefixName;
}
public void setPrefixName(String prefixName) {
this.prefixName = prefixName;
}
public String getSuffixName() {
return suffixName;
}
public void setSuffixName(String suffixName) {
this.suffixName = suffixName;
}
}
2.3 编写JsonConfiguration配置类
package com.david.learn.first.config;
import com.david.learn.first.service.JsonConvertService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConditionalOnClass(JsonConvertService.class)
@EnableConfigurationProperties(JsonProperties.class)
public class JsonConfiguration {
private JsonProperties jsonProperties;
@Autowired
public JsonConfiguration(JsonProperties jsonProperties) {
this.jsonProperties = jsonProperties;
}
@Bean
@ConditionalOnMissingBean(JsonConvertService.class)
public JsonConvertService jsonConvertService() {
JsonConvertService jsonConvertService = new JsonConvertService();
jsonConvertService.setPrefixName(jsonProperties.getPrefixName());
jsonConvertService.setSuffixName(jsonProperties.getSuffixName());
return jsonConvertService;
}
}
2.4 将配置类的全路径名配置到spring.factories文件中
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.david.learn.first.config.JsonConfiguration
如果是多个配置类,则用英文, 隔开,keyorg.springframework.boot.autoconfigure.EnableAutoConfiguration 保持不变
2.5 提供starter方式
????用maven的打包命令,install是将jar包打到本地仓库,deploy则打包到maven的私服仓库,只需要将GAV信息提供给调用方,在调用项目的pom文件引入即可
<groupId>com.david.learn</groupId>
<artifactId>first-demo-spring-boot-starter</artifactId>
<version>0.0.2-SNAPSHOT</version>
注意:在大厂生产环境不会用SNAPSHOT包,而是打稳定的包不会被别人覆盖 以上就完成了手写一个starter的步骤,再去看原理就懂了,为啥要按照约定去spring.factories文件里配置上配置类的全限定名(类的包路径+类名) ????整体上看写好的starter结构是这样
三、Github代码
代码地址:https://github.com/BillDavidup/multi-starter-demo 如果安装了git,则可使用git克隆代码到本地:git clone git@github.com:BillDavidup/multi-starter-demo.git
|