1 @Conditional
实现按照条件注入组件
需求:按照当前系统的环境注入不同的Person对象
- 如何获取当前系统的环境呢
@Test
public void testGetEnv(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
// 获取环境信息
ConfigurableEnvironment environment = applicationContext.getEnvironment();
String os = environment.getProperty("os.name");
log.info("当前系统为:{}",os);
}
1.1 @Conditional
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
/**
* All {@link Condition}s that must {@linkplain Condition#matches match}
* in order for the component to be registered.
*/
Class<? extends Condition>[] value();
}
- 可以放下类上和方法上,值为Condition的子类
1.2 Condition接口
org.springframework.context.annotation.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 registration.
*/
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
matches 方法说明
- 返回值:true表示条件匹配成功,false表示匹配失败
- context:上下文环境
- metadata:注释信息
public class ConditionIntroduction implements Condition {
/**
*
* @param context 上下文环境
* @param metadata 上下文环境
* @return true表示条件匹配成功,false表示匹配失败
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 获取ioc容器的Bean工厂
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 获取类加载器
ClassLoader classLoader = context.getClassLoader();
// 获取环境信息
Environment environment = context.getEnvironment();
// 获取bean的定义注册类:
// 可以使用BeanDefinitionRegistry查询注册了哪些类,
// 也可以使用它注册一个Bean
// 移除一个Bean的定义
// 判断容器中是否已经有一个Bean的定义
BeanDefinitionRegistry registry = context.getRegistry();
return false;
}
}
1.3 应用案例
实现上述的需求:在Mac系统注入乔布斯,在Windows系统注入比尔盖茨
- 提供一个Mac系统的条件判断
@Slf4j
public class MacOsCondition implements Condition {
/**
*
* @param context 上下文环境
* @param metadata 上下文环境
* @return true表示条件匹配成功,false表示匹配失败
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
String mac = environment.getProperty("os.name");
log.info("当前系统为: {}",mac);
boolean isMAc = mac.contains("Mac");
return isMAc;
}
}
- 提供一个Windows系统的条件判断
@Slf4j
public class MacOsCondition implements Condition {
/**
*
* @param context 上下文环境
* @param metadata 上下文环境
* @return true表示条件匹配成功,false表示匹配失败
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
String mac = environment.getProperty("os.name");
log.info("当前系统为: {}",mac);
boolean isMAc = mac.contains("Mac");
return isMAc;
}
}
- 使用@Conditional注解,进行注入
@Configuration
@ComponentScan(value = {"study.wyy.spring.anno.learn"})
public class MainConfig {
/**
* @Bean : 给容器中注册一个一个bean
* 类型为返回值类型
* id默认为方法名
*
*/
@Bean
@Scope("singleton")
@Lazy
Person person(){
System.out.println("创建Person");
Person kobe = new Person("Kobe", 20);
return kobe;
}
@Bean
@Conditional(MacOsCondition.class)
Person jobs(){
Person jobs = new Person("Jobs", 60);
return jobs;
}
@Bean
@Conditional(WindowsCondition.class)
Person gates(){
Person gates = new Person("Gates", 60);
return gates;
}
}
- 测试:本人电脑为Mac
@Test
public void testConditionOnMac() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Map<String, Person> beansOfType = applicationContext.getBeansOfType(Person.class);
Collection<Person> values = beansOfType.values();
List<Person> jobs = values.stream().filter(v -> v.getName().equals("Jobs")).collect(Collectors.toList());
Assert.assertThat(jobs.size(), equalTo(1));
Assert.assertThat(jobs.get(0).getName(), equalTo("Jobs"));
List<Person> gates = values.stream().filter(v -> v.getName().equals("Gates")).collect(Collectors.toList());
Assert.assertThat(gates.size(), equalTo(0));
}