spring boot 打包 jar 实现第三方零配置引用
springboot方便了我们将模块化的工程打成jar包供第三方使用,第三方可以使用多种配置方式进行引用,但是我觉得最大的诚意应该是实现零配置,第三方只需要在pom文件中指定jar引用信息即可,那么如何实现呢,请往下看。
springboot starter可以完成此目的,
实现starter 有以下步骤:
starter 命名
编写自动配置类,用来初始化相关的 bean ;
在resources/META-INF/下创建配置自动配置类的配置文件 spring.factories ;
自定义属性实体类,声明 starter 的应用配置属性 ;
以下详细步骤:
1. 给 starter 命名
也就是我们使用它的时候在 pom 中引用的 artifactId。命名有有规则的,官方规定:
官方的 starter 的命名格式为 spring-boot-starter-{name} ,例如上面提到的 spring-boot-starter-actuator。
非官方的 starter 的命名格式为 {name}-spring-boot-starter,我们把自定的 starter 命名为 statistics-spring-boot-starter,命名在 pom 文件里。
<groupId>statistics.springcloud</groupId>
<artifactId>statistics-spring-boot-starter</artifactId>
<packaging>jar</packaging>
<version>1.5-SNAPSHOT</version>
2. 引入自动配置包及其它相关依赖包
实现 starter 主要依赖自动配置注解,所以要在 pom 中引入自动配置相关的两个 jar 包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
除此之外,依赖的其他包当然也要引进来。
3. 创建 spring.factories 文件
在 resource/META-INF 目录下创建名称为 spring.factories 的文件,为什么在这里?当 Spring Boot 启动的时候,会在 classpath 下寻找所有名称为 spring.factories 的文件,然后运行里面的配置指定的自动加载类,将指定类(一个或多个)中的相关 bean 初始化。
例如本例中的配置信息是这样的:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
statistics.springcloud.boot.starter.example.StatisticsAutoConfigure
等号前面是固定的写法,后面就是我们自定义的自动配置类的路径了,如果有多个的话,用英文逗号分隔开。
4. 编写自动配置类
自动配置类是用来初始化 starter 中的相关 bean 的。可以说是实现 starter 最核心的功能。
@Configuration
@ConditionalOnClass(StatisticsService.class)
@EnableConfigurationProperties(StatisticsProperties.class)
@Slf4j
public class StatisticsAutoConfigure {
@Autowired
private StatisticsProperties statisticsProperties;
@Bean
@ConditionalOnMissingBean(StatisticsService.class)
@ConditionalOnProperty(prefix = "statistics.example",value = "enabled", havingValue = "true")
StatisticsService statisticsService(){
return new StatisticsService(statisticsProperties);
}
@Value("${data.statistics.host}")
String host;
/**
* 此处初始化的后续工程需要用到的bean,host变量需要在第三方工程配置,或者使用默认值
* @return
* @throws IOException
*/
@Bean
public StatisticsClient iniStatisticsClient() throws IOException {
return new StatisticsClientImpl("appname","password",host);
}
}
@Configuration 这个不用解释,表示这是个自动配置类,我们平时做项目时也会用到,一般是用作读取配置文件的时候。
@ConditionalOnClass(StatisticsService.class) :
只有在 classpath 中找到 StatisticsService 类的情况下,才会解析此自动配置类,否则不解析。
@EnableConfigurationProperties(StatisticsProperties.class):
启用配置类。
@Bean:实例化一个 bean 。
@ConditionalOnMissingBean(StatisticsService.class):
与 @Bean 配合使用,只有在当前上下文中不存在某个 bean 的情况下才会执行所注解的代码块,也就是当前上下文还没有 StatisticsService 的 bean 实例的情况下,才会执行 statisticsService() 方法,从而实例化一个 bean 实例出来。
@ConditionalOnProperty:
当应用配置文件中有相关的配置才会执行其所注解的代码块。
这个类的整体含义就是: 当 classpath 中存在 StatisticsService 类时解析此配置类,什么情况下才会在 classpath 中存在呢,就是项目引用了相关的 jar 包。并且在上下文中没有 StatisticsService 的 bean 实例的情况下,new 一个实例出来,并且将应用配置中的相关配置值传入。
5. 实现属性配置类
@Data
@ConfigurationProperties("statistics.example")
public class StatisticsProperties {
private String host;
private int port;
}
配置类很简单,只有两个属性,一个 host ,一个 port 。配置参数以 statistics.example 作为前缀。稍后我们在使用这个 starter 的时候会看到如何声明配置属性。
6. 实现相关功能类
也就是前面一直提到的 StatisticsService,其实严格来讲,这个业务功能类不应该放在 starter 中,应该放在单独的 jar 包里,但是此处 demo 非常简单,也就在这里写了。
@Slf4j
public class StatisticsService {
private String host;
private int port;
public StatisticsService(StatisticsProperties statisticsProperties){
this.host = statisticsProperties.getHost();
this.port = statisticsProperties.getPort();
}
public void print(){
log.info(this.host + ":" +this.port);
}
}
一个构造函数和一个 print 方法。
1. 在第三方项目中引用, pom 中引用
<dependency>
<groupId>statistics.springcloud</groupId>
<artifactId>statistics-spring-boot-starter</artifactId>
<version>1.5-SNAPSHOT</version>
</dependency>
2. 应用配置项
创建 application.yml ,配置如下:
server:
port: 3801
statistics:
example:
enabled: true # 开启才生效
host: 127.0.0.1
port: 3801
3. 调用 StatisticsService 的服务方法
@RestController
@RequestMapping(value = "use")
public class UseController {
@Autowired
private StatisticsService statisticsService;
@GetMapping(value = "print")
public void print(){
statisticsService.print();
}
}
还可以将jar包的配置文件写个提示信息配置,这样第三方在配置application.yml 或者application.properties时,可以有人性化的自动提示,步骤如下:
1、在需要打包的jar工程中resource/META-INF下,配置spring-configuration-metadata.json文件
{
"hints": [
],
"groups": [
{
"name": "statistics",
"type": "java.lang.String"
}
],
"properties": [
{
"name": "example.host",
"type": "java.lang.String"
}
]
}
2、pom添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>
这样既可实现在第三方应用引用该jar包进行配置时会有自动提示弹出,非常方便