深入浅出自定义创建spring-boot-starter
https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.developing-auto-configuration
快速入手
第一步:新建模块
第二步:修改依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>microservices</artifactId>
<groupId>com.example</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>test-spring-boot-starter</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
添加spring-boot-starter和spring-boot-configuration-processor这两个依赖。
第三步:新建Properties配置类
@ConfigurationProperties(prefix = "test")
public class TestProperties {
/**
* this is name
*/
private int name;
/**
* this is address
*/
private String address;
public int getName() {
return name;
}
public void setName(int name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "TestProperties{" +
"name=" + name +
", address='" + address + '\'' +
'}';
}
}
第四步:定义 AutoConfiguration,一个主配置,两个辅配置主要用来验证注解效果。
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "test", value = "enable", havingValue = "true", matchIfMissing = true)
@AutoConfigureAfter({AfterAutoConfiguration.class})
@AutoConfigureBefore({BeforeAutoConfiguration.class})
@EnableConfigurationProperties(TestProperties.class)
public class TestAutoConfiguration {
private static final Logger logger = LoggerFactory.getLogger(TestAutoConfiguration.class);
public TestAutoConfiguration(TestProperties properties) {
logger.info("TEST INIT ...... " + properties.toString());
}
}
@Configuration
public class AfterAutoConfiguration {
private static final Logger logger = LoggerFactory.getLogger(BeforeAutoConfiguration.class);
public AfterAutoConfiguration() {
logger.info("After INIT ...... ");
}
}
@Configuration
public class BeforeAutoConfiguration {
private static final Logger logger = LoggerFactory.getLogger(BeforeAutoConfiguration.class);
public BeforeAutoConfiguration() {
logger.info("Before INIT ...... ");
}
}
第五步:在resources目录下新建META-INF文件夹和spring.factories文件
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.starter.config.TestAutoConfiguration, \
com.example.starter.config.BeforeAutoConfiguration, \
com.example.starter.config.AfterAutoConfiguration
整体结构图
第八步:maven clean install 本地仓库
第九步:在另一个模块使用starter
<dependency>
<groupId>com.example</groupId>
<artifactId>test-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
第十步:配置yml
test:
address: abcd
name: 15
最后:查看效果
c.e.s.config.BeforeAutoConfiguration : After INIT ......
c.e.s.config.TestAutoConfiguration : TEST INIT ...... TestProperties{name=15, address='abcd'}
c.e.s.config.BeforeAutoConfiguration : Before INIT ......
AutoConfigureAfter和Before
@AutoConfigureAfter({AfterAutoConfiguration.class})
@AutoConfigureBefore({BeforeAutoConfiguration.class})
TestAutoConfiguration
简称为 A、B、T三个字母。
AutoConfigureAfter 源码注释
Hint for that an auto-configuration should be applied after other specified auto-configuration classes.
当前class 在指定类 后面加载
AutoConfigureBefore源码注释
Hint that an auto-configuration should be applied before other specified auto-configuration classes.
当前class 在指定类 前面加载
根据注释的意思我们得知,T在A后面,T在B前面。所以整个顺序为 A T B。
误区
首先AutoConfigureAfter和AutoConfigureBefore是作用于普通类的,普通的Configure无效。下面我们结合RocketMQAutoConfiguration 的源码来解释这个误区。
@Configuration
@EnableConfigurationProperties(RocketMQProperties.class)
@ConditionalOnClass({MQAdmin.class})
@ConditionalOnProperty(prefix = "rocketmq", value = "name-server", matchIfMissing = true)
@Import({MessageConverterConfiguration.class, ListenerContainerConfiguration.class,
ExtProducerResetConfiguration.class, ExtConsumerResetConfiguration.class,
RocketMQTransactionConfiguration.class})
@AutoConfigureAfter({MessageConverterConfiguration.class})
@AutoConfigureBefore({RocketMQTransactionConfiguration.class})
public class RocketMQAutoConfiguration implements ApplicationContextAware {}
依赖图
spring.factories内容
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.apache.rocketmq.spring.autoconfigure.RocketMQAutoConfiguration
在RocketMQAutoConfiguration中只有一个自动装配类,MessageConverterConfiguration和RocketMQTransactionConfiguration只是普通的配置类,所以我仿照这种写法实验后,这两个类不会进行加载,源码这里生效的原因是因为@Import(…)这个注解将普通配置类导入,其实这里是没有after和before的效果的,如果不相信可以将spring.factories demo的其余两个自动装配去掉打印控制台输出,然后加入@import注解后在观察输出。