SpringBoot自动装配
SpringBoot默认会扫描META-INF下面的spring.factories文件中的类的全路径进行装配
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
中对于上述进行了进一步的简化,SpringBoot
中提供了大量的@ConditionXxx注解. 例如提供了诸如:@ConditionalOnBean
、@ConditionalOnClass
、@ConditionalOnProperty
、@ConditionalOnMissingBean
等注解的支持. 还是以上述的发送短信案例为例,依据上面的代码做如下改动
@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更方便,提供的条件装配的注解种类更多
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.3.1</version>
</dependency>
@ConfigurationProperties(prefix = "redisson")
public class RedissonProperties {
private String host = "localhost";
private Integer port = 6379;
private Integer timeout = 10000;
private boolean ssl;
private String password;
}
// 根据前面的内容我们知道
// 仅当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);
}
}
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.bellamy.learn.redisson.configuration.RedissonAutoConfiguration
<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();
}
}