@Conditional注解详解

在使用Spring框架开发应用的过程中,大家都知道使用Spring开发应用程序,我们应用程序中大多数的Bean都是通过Spring的IOC容器来管理。将Bean注入到Spring IOC容器中的方式多种多样,可以通过组件扫描@ComponentScan注入、可以通过@Configuration和@Bean注入等。

本文我们要陈述的是如何根据不同的条件来判定到底注入那个Bean,即@Conditional注解的用法。

1、@Conditional介绍

首先我们先了解一下@Conditional注解,@Conditional是Spring4新提供的注解,它的作用是按照一定的条件进行判断,需要注入的Bean满足给定条件才可以注入到Spring IOC容器中。

我们先来看一下@Conditional注解的定义:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
	/**
	 * All {@link Condition Conditions} that must {@linkplain Condition#matches match}
	 * in order for the component to be registered.
	 */
	Class[] value();
}

从注解的定义我们可以看到,使用该注解我们需要传入的是一个Class数组,并且这些Class必须实现Condition接口,Condition接口定义如下:

@FunctionalInterface
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方法,matches方法返回的是一个boolean类型的数据,即返回true,代表@Conditional注解的Bean可以被注入到Spring IOC容器,返回false,@Conditional注解的Bean就不会被注入到Spring IOC容器。

2、@Conditional实例演示

一般情况下,我们的项目在不同阶段可能部署在不同的环境,比如开发阶段是部署在测试环境,验收阶段是部署在UAT环境,生产阶段是部署在生产环境。部署在不同的环境,我们的数据库链接肯定不一样,因此我们就以在不同环境获取不同数据库链接为例,来说明@Conditional注解的应用。

我们的例子要实现的是在配置文件中,如果我们配置当前环境为UAT环境,则返回UAT环境的数据库链接,如果配置的是生产环境,则返回生产环境的数据库链接。

首先是创建项目并添加必要的依赖,这里就不给出依赖配置的代码了,参考@ComponentScan向Spring IOC容器中注入组件。

在src/main/resources目录下创建配置文件Env.properties,用来配置环境信息。

创建entity包,写入测试数据类DataBase并重写toString方法,因为仅做演示,我们就简单些几个属性就可以了。

public class DataBase {
	private String host;
	private String user;
	private String password;
	
	public DataBase() {}
	
	public DataBase(String host,String user,String password) {
		this.host=host;
		this.user=user;
		this.password=password;
	}
	
	public String getHost() {
		return host;
	}
	public void setHost(String host) {
		this.host = host;
	}
	public String getUser() {
		return user;
	}
	public void setUser(String user) {
		this.user = user;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	@Override
	public String toString() {
		return "DataBase [host="+host+",user="+ user +",password="+ password +"]";
	}
}

创建condition包,写入Bean注入的判定条件,因为我们要实现的是在配置文件中,如果我们配置当前环境为UAT环境,则返回UAT环境的数据库链接,如果配置的是生产环境,则返回生产环境的数据库链接,所以我们需要两个条件,一个判定UAT环境的条件UatCondition,一个判定生产环境的条件ProCondition。

//UAT环境的条件UatCondition
public class UatCondition implements Condition {
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		Environment env = context.getEnvironment();
		if(env.getProperty("env").equals("UAT")){
			return true;
		}
		return false;
	}
}

//生产环境的条件ProCondition
public class ProCondition implements Condition {
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		Environment env = context.getEnvironment();
		if(env.getProperty("env").equals("Pro")){
			return true;
		}
		return false;
	}
}

创建config包,创建配置类DataBaseConfig通过注解@Configuration和@Bean向容器中注入组件。

//告诉Spring这是一个配置类
@Configuration 
//将properties配置文件中的值存储到Spring的 Environment中,Environment接口提供方法去读取配置文件中的值,参数是properties文件中定义的key值。
@PropertySource("classpath:Env.properties")
public class DataBaseConfig {
	@Bean
	@Conditional({ProCondition.class})
	public DataBase proDataBase(){
		return new DataBase("192.168.0.1","pro","222222");
	}
	
	@Bean
	@Conditional(UatCondition.class)
	public DataBase uatDataBase(){
		return new DataBase("127.0.0.1","ron","111111");
	}
}

如果在配置文件中,我们的env配置为UAT,则返回127.0.0.1的DataBase信息,env配置为Pro,则返回192.168.0.1的DataBase信息。

项目结构如下:
@Conditional注解详解_第1张图片

3、测试

创建单元测试ConditionTest,写入测试代码如下:

public class ConditionTest {
	@Test
	public void test() {
		AnnotationConfigApplicationContext application = new AnnotationConfigApplicationContext(DataBaseConfig.class);
		
		String[] names = application.getBeanDefinitionNames();
		for (String name : names) {
			System.out.println(name);
		}
		
		DataBase dataBase = application.getBean(DataBase.class);
		System.out.println(dataBase.toString());
	}
}

当我们在配置文件写入如下内容

env=UAT

执行单元测试打印出的dataBase结果为:

DataBase [host=127.0.0.1,user=ron,password=111111]

当我们在配置文件写入如下内容

env=Pro

执行单元测试打印出的dataBase结果为:

DataBase [host=192.168.0.1,user=pro,password=222222]

小结:

本文我们通过实例的形式阐述了@Conditional的概念及应用,希望大家共勉。

代码参见:https://download.csdn.net/download/zyhlwzy/11181205

你可能感兴趣的:(Java,Spring,MVC,@Conditional)