默认状况下,Spring中定义的bean在应用程序启动时会所有装配,无论当前运行的是哪一个环境(Dev,QA或者Prod),也无论当前运行的是什么系统(Windows或者Linux),但有些使用场景下,咱们可能须要条件化的装配某些bean,即当知足某一条件时,装配某些bean,当不知足某一条件时,就忽略掉某些bean。java
这个条件能够很简单,好比当某个jar包存在时,当存在某个环境变量时,也能够很复杂。linux
针对这个使用场景,Spring中提供了@Conditional
注解来实现条件化的bean。git
为了更好的理解,咱们经过具体的代码示例来理解下条件化的bean的实现方式。github
因为Windows系统和Linux系统显示列表的命令不一样,Windows下是dir,Linux下是ls,所以咱们的需求是,应用程序启动时自动根据当前系统装配须要的bean,好比个人电脑系统是Windows 7,那就只装配Windows系统所须要的bean。spring
首先,定义一个接口ListService,该接口只包含一个方法showListCmd:windows
package chapter03.conditional;
public interface ListService {
String showListCmd();
}
复制代码
而后定义该接口的2个实现类WindowsListService和LinuxListService:微信
package chapter03.conditional;
public class WindowsListService implements ListService {
public WindowsListService() {
System.out.println("This is WindowsListService constructor");
}
@Override
public String showListCmd() {
return "dir";
}
}
复制代码
package chapter03.conditional;
public class LinuxListService implements ListService {
public LinuxListService() {
System.out.println("This is LinuxListService constructor");
}
@Override
public String showListCmd() {
return "ls";
}
}
复制代码
而后分别定义Windows系统和Linux系统的判断条件:ide
package chapter03.conditional;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
return conditionContext.getEnvironment().getProperty("os.name").contains("Windows");
}
}
复制代码
package chapter03.conditional;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
return conditionContext.getEnvironment().getProperty("os.name").contains("Linux");
}
}
复制代码
值得注意的是,这2个类都须要实现Condition接口,并重写方法matches(),若是该方法返回true时,使用该条件的1个或多个bean就会被装配,若是该方法返回false,使用该条件的1个或多个bean就会被忽略。测试
而后,定义Java配置类ConditionalConfig:spa
package chapter03.conditional;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ConditionalConfig {
@Bean
@Conditional(WindowsCondition.class)
public ListService windowsListService() {
return new WindowsListService();
}
@Bean
@Conditional(LinuxCondition.class)
public ListService linuxListService() {
return new LinuxListService();
}
}
复制代码
这里声明bean时除了使用@Bean注解,还使用了@Conditional注解,这个注解是实现条件化的bean的关键,它的参数能够传递任何实现了Condition接口并重写了matches()方法的类,这里传递的是咱们上面定义的WindowsCondition和LinuxCondition。
最后,咱们定义一个Main类,在其main()方法中添加以下测试代码:
package chapter03.conditional;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConditionalConfig.class);
ListService listService = context.getBean(ListService.class);
System.out.println(context.getEnvironment().getProperty("os.name") + "系统下的列表命令为:" + listService.showListCmd());
context.close();
}
}
复制代码
运行结果以下所示:
This is WindowsListService constructor
Windows 7系统下的列表命令为:dir
从运行日志能够看出,因为当前系统是Windows 7,咱们声明的linuxListService bean并无被装配。
源码地址:github.com/zwwhnly/spr…,欢迎下载。
汪云飞《Java EE开发的颠覆者:Spring Boot实战》
Craig Walls 《Spring实战(第4版)》
最后,欢迎关注个人微信公众号:「申城异乡人」,全部博客会同步更新。