ConfigurationCondition接口相对于Condition接口多了一个getConfigurationPhase方法,用来指定条件判断的阶段,是在解析配置类的时候过滤还是在创建bean的时候过滤。
@Conditional使用的3步骤
-
自定义一个类,实现Condition或ConfigurationCondition接口,实现matches方法
-
在目标对象上使用@Conditional注解,并指定value的指为自定义的Condition类型
-
启动spring容器加载资源,此时@Conditional就会起作用了
案例1:阻止配置类的处理
在配置类上面使用@Conditional,这个注解的value指定的Condition当有一个为false的时候,spring就会跳过处理这个配置类。
自定义一个Condition类:
package com.javacode2018.lesson001.demo25.test3;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class MyCondition1 implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return false;
}
}
matches方法内部我们可以随意发挥,此处为了演示效果就直接返回false。
来个配置类,在配置类上面使用上面这个条件,此时会让配置类失效,如下:
package com.javacode2018.lesson001.demo25.test3;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@Conditional(MyCondition1.class) //@1
@Configuration
public class MainConfig3 {
@Bean
public String name() { //@1
return “路人甲Java”;
}
}
@1:使用了自定义的条件类
@2:通过@Bean标注这name这个方法,如果这个配置类成功解析,会将name方法的返回值作为bean注册到spring容器
来个测试类,启动spring容器加载MainConfig3配置类,如下:
package com.javacode2018.lesson001.demo25;
import com.javacode2018.lesson001.demo25.test3.MainConfig3;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.util.Map;
public class ConditionTest {
@Test
public void test3() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig3.class);
Map<String, String> serviceMap = context.getBeansOfType(String.class);
serviceMap.forEach((beanName, bean) -> {
System.out.println(String.format(“%s->%s”, beanName, bean));
});
}
}
test3中,从容器中获取String类型的bean,运行test3没有任何输出。
我们可以将MainConfig3上面的@Conditional去掉,再次运行输出:
name->路人甲Java
案例2:阻止bean的注册
来个配置类,如下:
package com.javacode2018.lesson001.demo25.test4;
import com.javacode2018.lesson001.demo25.test3.MyCondition1;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MainConfig4 {
@Conditional(MyCondition1.class) //@1
@Bean
public String name() {
return “路人甲Java”;
}
@Bean
public String address() {
return “上海市”;
}
}
上面2个方法上面使用了@Bean注解来定义了2个bean,name方法上面使用了@Conditional注解,这个条件会在name这个bean注册到容器之前会进行判断,当条件为true的时候,name这个bean才会被注册到容器。
ConditionTest中新增个测试用例来加载上面这个配置类,从容器中获取String类型所有bean输出,代码如下:
@Test
public void test4() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig4.class);
Map<String, String> serviceMap = context.getBeansOfType(String.class);
serviceMap.forEach((beanName, bean) -> {
System.out.println(String.format(“%s->%s”, beanName, bean));
});
}
运行输出:
address->上海市
可以看到容器中只有一个address被注册了,而name这个bean没有被注册。
案例3:bean不存在的时候才注册
需求
IService接口有两个实现类Service1和Service1,这两个类会放在2个配置类中通过@Bean的方式来注册到容器,此时我们想加个限制,只允许有一个IService类型的bean被注册到容器。
可以在@Bean标注的2个方法上面加上条件限制,当容器中不存在IService类型的bean时,才将这个方法定义的bean注册到容器,下面来看代码实现。
代码实现
条件判断类:OnMissingBeanCondition
package com.javacode2018.lesson001.demo25.test1;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.Condition;
import org.springf