@Conditional主要用来提供自动装配的条件约束,一般和@Configuration和@Bean配合使用。
首先先来看一下它的结构:
@Target({
ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
Class<? extends Condition>[] value();
}
可以看出来,该注解可以接收一个Condition类型的数组。而Condition是一个函数式接口,主要用来提供matches方法,**提供一个条件匹配规则,返回true表示可以注入Bean,反之则不注入。
**
@FunctionalInterface
public interface Condition {
boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2);
}
自定义Condition:
public class MyCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
String os = conditionContext.getEnvironment().getProperty("os.name");
// 如果电脑运行环境是Mac,那么返回true
// 如果你的电脑是window,这里输入Windows
if (os.contains("Mac OS X")) {
return true;
}
return false;
}
}
自定义配置类:
@Configuration
public class ConditionConfig {
@Conditional(MyCondition.class)
@Bean
// 只有MyCondition返回true时,这里才会加载这个Bean
public FirstBean getBean(){
return new FirstBean();
}
}
启动类:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConditionConfig.class);
// FirstBean是我自定义的Bean
FirstBean bean = context.getBean(FirstBean.class);
System.out.println(bean.toString());
}
}
结果:
如果这时候改一下逻辑,比如当环境为Window时候才返回true,那么结果会报错,报错如下:
SpringBoot中,对@Conditional做了一些拓展,扩展的注解如下:
这些注解只需要添加到@Configuration配置类的类级别或者方法级别时,根据每个注解的作用来传参即可。
ConditionalOnProperty:
@Configuration
@ConditionalOnProperty(value = "test.bean.enble", havingValue = "true", matchIfMissing = true)
public class ConditionConfig {
}
ConditionalOnBean:
@Configuration
@ConditionalOnBean(FirstBean.class)
public class ConditionConfig {
}
ConditionalOnResource:
@Configuration
@ConditionalOnResource(resources = "/test.properties")
public class ConditionConfig {
}
除了@Conditional注解类,在SpringBoot中还提供了spring-autoconfigure-metadata.properties文件来实现批量自动装配的条件配置。
起作用和@Conditional一样,只是将这些条件配置放在了配置文件中。同时,通过这种配置化的方式来实现条件过滤必须要遵循两个条件:
优势:
Starter组件主要有三个功能:
Starter的命名规范:
项目结构:
自定义配置类RedisAutoConfiguration:
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
@Configuration
@ConditionalOnClass(Redisson.class)
@EnableConfigurationProperties(RedissonProperties.class)
public class RedisAutoConfiguration {
RedissonClient redissonClient(RedissonProperties redissonProperties) {
Config config = new Config();
String prefix = "redis://";
if (redissonProperties.isSsl()) {
prefix = "rediss://";
}
SingleServerConfig singleServerConfig = config.useSingleServer().setAddress(prefix + redissonProperties.getHost() + ":" + redissonProperties.getPort())
.setConnectTimeout(redissonProperties.getTimeout());
if (!StringUtils.isEmpty(singleServerConfig)) {
singleServerConfig.setPassword(redissonProperties.getPassword());
}
return Redisson.create(config);
}
}
自定义配置类RedissonProperties:
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "my.redisson")
public class RedissonProperties {
private String host="localhost";
private String password;
private int port=6379;
private int timeout;
private boolean ssl;
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public int getTimeout() {
return timeout;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
public boolean isSsl() {
return ssl;
}
public void setSsl(boolean ssl) {
this.ssl = ssl;
}
}
spring.factories:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.config.RedisAutoConfiguration
application.properties:
my.redission=192.168.237.130
my.redission.port=6379
pom:
<parent>
<groupId>org.springframework.bootgroupId>
<version>2.3.5.RELEASEversion>
<artifactId>spring-boot-starter-parentartifactId>
parent>
<dependencies>
<dependency>
<groupId>org.redissongroupId>
<artifactId>redissonartifactId>
<version>3.11.1version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-configuration-processorartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.examplegroupId>
<artifactId>redis-spring-boot-starterartifactId>
<version>1.0-SNAPSHOTversion>
dependency>
dependencies>
完成以上步骤后,一个简单的手写Starter就完成了。