@Conditional
注解用于给容器中选择性添加Bean
测试案例,根据不同的操作系统添加不同的Bean:
测试类
package com.liu.demo;
import java.util.Map;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.Environment;
import com.liu.demo.bean.Person;
import com.liu.demo.config.PersonConfig;
public class IocTest {
@Test
public void test02() {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(PersonConfig.class);
//获取系统运行环境
//getEnvironment 返回与给定key关联的属性值,如果不能解析key,则返回null。
Environment environment = applicationContext.getEnvironment();
String property = environment.getProperty("os.name");
//如果是win10系统,则输出Windows 10
System.out.println("当前系统是:" + property);
//getBeanNamesForType 返回与给定类型(包括子类)匹配的bean的名称,根据bean定义或FactoryBeans中getObjectTypein的值判断。
String[] beanNames = applicationContext.getBeanNamesForType(Person.class);
for (String beanName : beanNames) {
System.out.println("包含的所有Bean的名称" + beanName);
}
//getBeansOfType 返回与给定对象类型(包括子类)匹配的bean实例,从bean定义或FactoryBeans中getObjectType的值判断。
Map<String, Person> beans = applicationContext.getBeansOfType(Person.class);
System.out.println("包含的所有Bean的实例:" + beans);
}
}
Person类
Person对象的一些属性
package com.liu.demo.bean;
public class Person {
private String name;
private Integer age;
private String sex;
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", sex=" + sex + "]";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Person(String name, Integer age, String sex) {
super();
this.name = name;
this.age = age;
this.sex = sex;
}
public Person() {
super();
// TODO Auto-generated constructor stub
}
}
配置文件PersonConfig
@Configuration
表明这个类声明了一个或多个@Bean方法,交给Spring容器处理,以便在运行时为这些bean生成bean定义和服务请求,
@Conditional
指示只有当所有指定条件匹配时,组件才有资格注册。传入参数为判断条件,条件是可以在注册bean定义之前通过编程确定的任何状态,此处编写了两个类WindowsCondition
和 LinuxCondition
,继承了Condition
接口,并实现matches
方法
package com.liu.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import com.liu.demo.bean.Person;
import com.liu.demo.condition.LinuxCondition;
import com.liu.demo.condition.WindowsCondition;
@Configuration
public class PersonConfig {
@Bean
public Person person() {
return new Person("zhangsan", 18, "男");
}
/**
* @Conditional 注解可用于方法、类上,满足条件后添加Bean
* @return
*/
@Conditional(WindowsCondition.class)
@Bean
public Person person01() {
return new Person("001", 18, "男");
}
@Conditional(LinuxCondition.class)
@Bean
public Person person02() {
return new Person("002", 18, "男");
}
}
判断条件(WindowsCondition类、LinuxCondition类)
package com.liu.demo.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{
/**
* ConditionContext 上下文信息作为判断条件
* AnnotatedTypeMetadata 定义对特定类型(classor方法)的注释的访问,其形式不一定需要加载类。
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// TODO 判断是否是Windows系统
Environment environment = context.getEnvironment();
String property = environment.getProperty("os.name");
if(property.contains("Windows")) {
return true;
}
return false;
}
}
matches
方法中的参数context
可以获取到的内容有 获取bean工厂、获取类加载器、获取当前环境、获取bean定义的注册表等等 ,如下所示
package com.liu.demo.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{
/**
* ConditionContext 上下文信息作为判断条件
* AnnotatedTypeMetadata 定义对特定类型(classor方法)的注释的访问,其形式不一定需要加载类。
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//context可获取到的内容
//获取bean工厂
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//获取类加载器
ClassLoader classLoader = context.getClassLoader();
//获取当前环境
Environment environment = context.getEnvironment();
/**
* 获取bean定义的注册表
* 可用于判断是否包含某个bean
* 可以添加bean
* 等等
*/
BeanDefinitionRegistry registry = context.getRegistry();
// TODO 判断是否是Linux系统
String property = environment.getProperty("os.name");
if(property.contains("Linux")) {
return true;
}
return false;
}
}
结果
当前系统是:Windows 10
包含的所有Bean的名称person
包含的所有Bean的名称person01
包含的所有Bean的实例:{person=Person [name=zhangsan, age=18, sex=男], person01=Person [name=001, age=18, sex=男]}
补充 @Import
注解
@Import
注解有类似的功能,传入一个实现了ImportSelector
接口的类,该类实现selectImports
方法,返回要导入的全类名,在实现的selectImports
方法中可以进行自定义的处理
示例:
package com.liu.demo.selecter;
import java.util.Set;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
public class MyImportSelector implements ImportSelector{
/**
* AnnotationMetadata 注释元数据
*/
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
// TODO Auto-generated method stub
//获取注释类型 eg:[org.springframework.context.annotation.Configuration, org.springframework.context.annotation.Import]
Set<String> allAnnotationAttributes = importingClassMetadata.getAnnotationTypes();
System.out.println("---" + allAnnotationAttributes.toString());
//返回全类名
return new String[] {"com.liu.demo.bean.Red"};
}
}