Spring注解驱动开发学习总结3:组件注册之@Conditional详解
1、使用@Conditional 按照条件注册bean
使用@Conditional 注解,可以按照一定的条件进行判断,满足条件的话,才会给容器中注册bean。在springboot框架中大量地使用了该注解。
1、查看@Conditional 注解,可以看到该注解的参数value,可以传一个实现了Condition接口的实现类的数组;
public @interface Conditional {
Class<? extends Condition>[] value();
}
2、接着查看下Condition接口,可以看到只需要实现它的一个方法matches,用来判断条件是否满足。
入参共有2个参数:
1)ConditionContext:判断条件能使用的上下文环境(包括ioc的beanfactory,类加载器,环境信息,bean定义的注册类)
2)AnnotatedTypeMetadata:注释信息
基于上面的两个参数里的信息,就可以进行来做判断,是否需要注册该实例的bean了。
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 registration.
*/
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
接着上一篇文章,继续在容器中注册id为bill的person实例,和id为linus的person实例。
当系统是Windows的时候,bill的person实例就注册进容器中;
当系统是linux的时候,linus的person就注册进实例中。
下面以这个小功能进行举例。
1.1 构建自定义Condition
1)构建判断是否是Linux系统的自定义条件实现类:com/example/condition/LinuxCondition.java
我们可以看到,从context可以获得很多信息,可以供给我们使用判断:
- 可以获取到ioc使用的beanfactory;
- 可以获取到类加载器
- 可以获取到当前环境信息
- 可以获取到bean定义的注册类
package com.example.condition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 1、可以获取到ioc使用的beanfactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 2、可以获取到类加载器
ClassLoader classLoader = context.getClassLoader();
// 3、可以获取到当前环境信息
Environment environment = context.getEnvironment();
// 4、可以获取到bean定义的注册类
BeanDefinitionRegistry registry = context.getRegistry();
// 通过environment获取当前系统
String property = environment.getProperty("os.name");
if (property.toUpperCase().contains("LINUX")) {
return true;
}
return false;
}
}
1)构建判断是否是Windows系统的自定义条件实现类:com/example/condition/WindowsCondition.java
package com.example.condition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 可以获取到当前环境信息
Environment environment = context.getEnvironment();
// 通过environment获取当前系统,如果包含windows,那么就不是linux系统
String property = environment.getProperty("os.name");
if (property.toUpperCase().contains("WINDOWS")) {
return true;
}
return false;
}
}
1.2 按条件注入person实例
继续在上一篇博文的配置类MainConfig2中,继续添加两个person实例,只是这2个实例上面分别添加了对应的@Conditional注解。
当系统是Windows的时候,bill的person实例就注册进容器中;
当系统是linux的时候,linus的person就注册进实例中。
package com.example.config;
import com.example.bean.Person;
import com.example.condition.LinuxCondition;
import com.example.condition.WindowsCondition;
import org.springframework.context.annotation.*;
@Configuration
public class MainConfig2 {
@Conditional(WindowsCondition.class)
@Bean("bill")
public Person person01() {
return new Person("Bill Gates", 62);
}
@Conditional(LinuxCondition.class)
@Bean("linus")
public Person PERSON02() {
return new Person("Linus", 48);
}
}
1.3 构建测试方法
构建测试方法:testConditonal()。
测试方法中会打印当前系统的名称,并且会打印最终注入的person实例名称
@Test
public void testConditonal() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
System.out.println("\nioc容器已创建完成\n");
ConfigurableEnvironment environment = applicationContext.getEnvironment();
String property = environment.getProperty("os.name");
System.out.println("当前系统为: " + property);
String[] beanNamesForType = applicationContext.getBeanNamesForType(Person.class);
for (String beanName:beanNamesForType) {
System.out.println("注入容器的person实例的名称为:" + beanName);
}
}
1.4 测试
运行testConditonal()可以得到下图。
由于我的系统是ubuntu16.04,因此可以看到,只有linus的person实例成功注入了容器中。