SpringBoot自動裝配
- ImportSelector
- Registrar
約定優於配置
SpringBoot默認會掃描META-INF下面的spring.factories文件中的類的全路徑進行裝配
SpringFramework @Conditional
Conditional.class 是從Spring4.0開始提供的,通過當前註解可以實現多條件裝配;該註解需要搭配Condition.class接口使用. 以下是註解的內容
- 接口
public @interface Conditional {
Class<? extends Condition>[] value();
}
下面以接入短信服務商爲例;通過掃描我們在配置文件中配置使用哪家服務商然後自動進行裝配.
- 用於匹配
ucloud
服務商
public class UCloudConditional implements Condition {
private Properties properties;
@Override
public boolean matches
(ConditionContext conditionContext,
AnnotatedTypeMetadata annotatedTypeMetadata)
throws Exception{
properties = new Properties();
InputStream is = conditionContext.getResourceLoader()
.getResource("classpath:xxx.properties").getInputStream();
properties.load(is); // 這裏的properties文件可以自行定義
return StringUtils.isEmpty(properties.getProperty("sms.used"))
? false
"ucloud".equalsIgnoreCase(properties.getProperty("sms.used")); // 看當前是否匹配
- 用於匹配創藍服務商
public class ClConditional implements Condition {
private Properties properties;
// 內容差不多同上所示
@Override
public boolean matches
(ConditionContext conditionContext,
AnnotatedTypeMetadata annotatedTypeMetadata)
throws Exception{
properties = new Properties();
InputStream is = conditionContext.getResourceLoader().getResource("classpath:xxx.properties").getInputStream();
properties.load(is);
return StringUtils.isEmpty(properties.getProperty("sms.used"))
? true
: "cl".equalsIgnoreCase(properties.getProperty("sms.used"));
- 配置類
@Configuration
public class SMSMessageConfiguration {
@Bean
@Conditional(UCloudConditional.class)
public ISendMessageTemplate createUCloudTemplate() {
return new UCloudSendMessageTemplate();
}
@Bean
@Conditional(ClConditional.class)
public ISendMessageTemplate createClTemplate() {
return new ClSendMessageTemplate();
}
}
- 提供服務
public interface ISendMessageTemplate {
void sendMessage(String phone, String content);
}
public class ClSendMessageTemplate {
void sendMessage(String phone, String content){
System.out.printf("using chuanglan send msg, phone:%s, content:%s", phone, content);
}
}
public class UCloudSendMessageTemplate {
void sendMessage(String phone, String content){
System.out.printf("using ucloud send msg, phone:%s, content:%s", phone, content);
}
}
public class SendMessageTester {
@Autowired
private ISendMessageTemplate sendMessageTemplate;
/**
* 短信發送
*
* @param phone
* @param content
* @return
*/
@Test
public void testSend(){
sendMessageTemplate.sendMessage("13800138000", "Hi");
}
}
SpringBoot @ConditionXXX註解
通過如上案例會發現還是需要很多的代碼才能實現一個條件注入;因此在
SpringBoot
中對於上述進行了進一步的簡化,SpringBoot
中提供了大量的@ConditionXxx註解. 例如提供了諸如:@ConditionalOnBean
、@ConditionalOnClass
、@ConditionalOnProperty
、@ConditionalOnMissingBean
等註解的支持. 還是以上述的發送短信案例爲例,依據上面的代碼做如下改動
- configuration
@Configuration
public class SMSMessageConfiguration {
@Bean
@ConditionalOnProperty(name = "sms.used", havingValue = "ucloud")
public ISendMessageTemplate createUCloudTemplate() {
return new UCloudSendMessageTemplate();
}
@Bean
@ConditionalOnProperty(value = "sms.used", havingValue = "cl")
public ISendMessageTemplate createClTemplate() {
return new ClSendMessageTemplate();
}
}
- 測試
@SpringBootTest
public class SendMessageTester {
@Autowired
private ISendMessageTemplate sendMessageTemplate;
@Test
public void testSend(){
sendMessageTemplate.sendMessage("13800138000", "Hi");
}
}
通過上訴案例兩者都可以實現條件裝配,相比於SpringFramework框架提供的方式,SpringBoot更方便,提供的條件裝配的註解種類更多
手寫個starter(以Redis爲例)
- 依賴
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.3.1</version>
</dependency>
- properties
@ConfigurationProperties(prefix = "redisson")
public class RedissonProperties {
private String host = "localhost";
private Integer port = 6379;
private Integer timeout = 10000;
private boolean ssl;
private String password;
}
- configuration
// 根據前面的內容我們知道
// 僅當Redisson.class被使用到時才裝配
@ConditionalOnClass(Redisson.class)
// 激活配置
@EnableConfigurationProperties(RedissonProperties.class)
@Configuration
public class RedissonAutoConfiguration {
// 這裏是配置
@Bean
public RedissonClient newRedissonClient(RedissonProperties redissonProperties) {
Config config = new Config();
config.useSingleServer()
.setAddress(redissonProperties.getHost()
+ ":"
+ redissonProperties.getPort())
.setPassword(redissonProperties.getPassword())
.setConnectTimeout(redissonProperties.getTimeout());
return Redisson.create(config);
}
}
- spring.factories (MATA-INF)
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.bellamy.learn.redisson.configuration.RedissonAutoConfiguration
開啓提醒功能
- MAVEN依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
- 增加提示的配置內容
additional-spring-configuration-metadata.json(位置同上)
{
"properties": [
{
"name": "redisson.host",
"type": "java.lang.String",
"description": "redis服務地址.",
"defaultValue": "localhost"
},
{
"name": "redisson.prot",
"type": "java.lang.Integer",
"description": "redis服務端口號.",
"defaultValue": 6379
},
{
"name": "redisson.timeout",
"type": "java.lang.Integer",
"description": "redis服務連接超時時間.",
"defaultValue": 10000
},
{
"name": "redisson.ssl",
"type": "java.lang.Boolean",
"description": "ssl連接.",
"defaultValue": false
},
{
"name": "redisson.password",
"type": "java.lang.String",
"description": "redis密碼.",
"defaultValue": ""
}
]
}
在測試工程中引入如上的項目依賴
- 依賴
<dependency>
<groupId>org.bellamy.learn</groupId>
<artifactId>redis-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
redisson.host=127.0.0.1
redisson.port =6379
redisson.timeout=60000
- 開始測試
@RestController
public class TestController {
@Autowired
private RedissonClient client;
@GetMapping(value = "/operation")
public Object operation(String val) throws ExecutionException, InterruptedException {
RBucket<String> bucket = client.getBucket("name");
if (bucket.get() == null) {
bucket.set(val);
}
return bucket.get();
}
}