按条件注册bean之@Conditional
需求:我们希望某些bean在特定环境下才注册到IOC容器,比如,根据当前操作系统的不同,选择性的注册一些bean到IOC容器中。
初识@Conditional注解,我们看看其注释:
Indicates that a component is only eligible for registration when all {@linkplain #value specified conditions} match.
意思是只有组件符合注册条件,组件才会被注册到IOC容器中。然后看看@Conditional定义:
public @interface Conditional {
/**
* All {@link Condition Conditions} that must {@linkplain Condition#matches match}
* in order for the component to be registered.
*/
Class<? extends Condition>[] value();
}
可以看到此注解需要一个Class类型的数组,数组元素为Condition类型,同时从value()的注释可以看到,只有匹配到Condition的组件才会被注册。Condition是啥?
public interface Condition {
/**
* Determine if the condition matches.
* @param context the condition context
* @param metadata metadata of the {@link org.springframework.core.type.AnnotationMetadata class}
* or {@link org.springframework.core.type.MethodMetadata method} being checked
* @return {@code true} if the condition matches and the component can be registered,
* or {@code false} to veto the annotated component's registration
*/
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
Condition是一个函数式接口,因此我们需要实现该接口,matches()里面就是我们要定义的匹配规则。
假如我们现在有两个bean,Windows bean和Linux bean,我们希望如果当前应用运行环境为Windows,就只注册Windows bean,如果为Linux,就只注册Linux bean。
两个bean的定义:
public class Windows {
public Windows() {
System.out.println("===> windows bean created...");
}
}
public class Linux {
public Linux() {
System.out.println("===> linux bean created...");
}
}
那么要选择性的注册这两个bean,我们需要为他们分别定义一个Condition,并在matches中写上我们的匹配规则:
public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
String osName = environment.getProperty("os.name");
System.out.println("windows condition ===> " + osName);
if (osName.contains("Windows")) {
return true;
}
return false;
}
}
public class LinuxConditon implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
String property = environment.getProperty("os.name");
System.out.println("linux condition ===> " + property);
if (property.contains("linux")) {
return true;
}
return false;
}
}
在配置文件中配置我们的bean,同时注解上注册bean的条件:
@Configuration
public class AnnotationBeanConfig {
@Conditional({WindowsCondition.class})
@Bean("Bill Gates")
public Windows windows() {
return new Windows();
}
@Conditional({LinuxConditon.class})
@Bean("linus")
public Linux linux() {
return new Linux();
}
}
测试类:
public class AnnotationBeanTest {
@Test
public void testBeanConditonal() {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AnnotationBeanConfig.class);
System.out.println("===> IOC container created..." );
}
}
这里我们只创建IOC容器即可,因为在默认单例模式下,容器创建时就会把所有的单例bean注册到容器中。不清楚的可以看我上一篇博客:spring注解开发——bean的作用域和懒加载
结果:
windows condition ===> Windows 10
linux condition ===> Windows 10
===> windows bean created...
===> IOC container created...
可以看到,只有Windows bean注册到了容器中,在Linux环境下,大家可以自行去测试,看看是不是只有Linux bean被注册。