源码: https://github.com/nieandsun/spring-study
1 Conditional相关注解简介
在Springboot项目里我们可能会在开发中用到好多与Conditional相关的注解,如:
- @ConditionalOnClass
- @ConditionalOnBean
- @ConditionalOnMissingBean
- @ConditionalOnMissingClass
- @ConditionalOnProperty
等,其实根据英文我们可以很容易的知道这些注解的意思,但难的是很多时候根本想不起来用。
今天在玩spring源码的时候发现其实spring原生注解里只有 @Conditional这一个注解, 而上面列出来的这些与Conditional相关的注解其实是springboot对其进行扩展的,而且扩展的还挺丰富的,如下图所示:
2 @Conditional注解的简单使用
本篇主要来介绍一下@Conditional注解的使用。
场景描述: 当服务器以Win环境启动时,向IOC容器中注入xiaoming这个对象,以Linux环境启动时,向IOC容器中注入xiaohong这个对象。
(1) 准备两个Condition对象 — 作为对象注册条件类
- win环境的注册条件
package com.nrsc.springstudy.c08_Conditional.conditional;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
* Description: 该类作为bean的注册条件类,需要实现Condition接口,并实现其matches方法
*/
public class WinCondition implements Condition {
/***
*
* @param context 判断条件能使用的上下文(环境)
* @param metadata 注释信息
* @return
*/
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//通过context可以拿到很多信息,如:
// //可以获取到IOC容器使用的beanFactory
// ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// //可以获取到类加载器
// ClassLoader classLoader = context.getClassLoader();
// //获取bean定义的注册类
// BeanDefinitionRegistry registry = context.getRegistry();
// //获取资源加载器
// ResourceLoader resourceLoader = context.getResourceLoader();
//todo 如果运行环境为win则返回true
//获取当前环境信息
Environment environment = context.getEnvironment();
//获取当前运行环境的系统名称
String property = environment.getProperty("os.name");
if (property.contains("Windows")) {
return true;
}
return false;
}
}
- linux环境的注册条件
package com.nrsc.springstudy.c08_Conditional.conditional;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
* Description: 该类作为bean的注册条件类,需要实现Condition接口,并实现其matches方法
*/
public class LinuxCondition implements Condition {
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//todo 如果运行环境为linux则返回true
//获取当前环境信息
Environment environment = context.getEnvironment();
//获取当前运行环境的系统名称
String property = environment.getProperty("os.name");
if (property.contains("linux")) {
return true;
}
return false;
}
}
(2)利用@Conditional注解实现功能
package com.nrsc.springstudy.c08_Conditional.config;
import com.nrsc.springstudy.c08_Conditional.conditional.LinuxCondition;
import com.nrsc.springstudy.c08_Conditional.conditional.WinCondition;
import com.nrsc.springstudy.domain.Student;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@Configuration
public class C08Config {
/***
* 注册xiaoming的注册条件使用WinCondition.class
* @return
*/
@Conditional(WinCondition.class)
@Bean("xiaoming")
public Student student1() {
System.out.println("给容器中添加小明同学。。。win");
return new Student("xiaoming", 10);
}
/***
* 注册xiaohong的注册条件使用WLinuxCondition.class
* @return
*/
@Conditional(LinuxCondition.class)
@Bean("xiaohong")
public Student student2() {
System.out.println("给容器中添加小红同学。。。lin");
return new Student("xiaohong", 9);
}
}
(3) spring 环境启动类
import com.nrsc.springstudy.c08_Conditional.config.C08Config;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Test_08_Conditional {
@Test
public void test01() {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(C08Config.class);
System.out.println("IOC容器创建完成........");
}
}
(4) 测试
win系统下运行test01方法,控制台打印结果如下,说明当以win环境启动时,确实只有xiaoming被注册到了IOC容器中。
运行环境参数VM options 设置为 -Dos.name=linux (— 以linux环境运行),然后运行test01方法,控制台打印结果如下,说明以linux环境启动时,确实只有xiaohong被注册到了IOC容器中。
3 注意
Conditional相关的注解在真实项目中很有用,这里也给自己提醒一下,在实际开发中心里一定要经常有这根弦,遇到相关问题时,千万不要忘记使用。