@Condition注解功能还是比较强大的,一般配合其他注解一起使用去配置Bean。从使用中可以深切体会到Spring设计的代码复用性高和耦合性低的特点,因为这个注解类似于模块化的条件判断语句。
- 项目结构:
- 条件类的实现,其实现了Spring定义的Condition类
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class MacOSCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
//1
conditionContext.getBeanFactory();
//2
conditionContext.getClassLoader();
//3
String property = conditionContext.getEnvironment().getProperty("os.name");
//4
conditionContext.getRegistry();
//5
conditionContext.getResourceLoader();
//annotatedTypeMetadata.getAllAnnotationAttributes();
if(property.contains("Mac")){
return true;
}
return false;
}
}
观察代码,我们可以发现:从重写方法的两个参数中可以获取应用上下文的许多变量参数,从而判断一些条件并加上一些逻辑代码;再返回boolean,告诉Spring是否执行相应的操作。
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) {
String property = conditionContext.getEnvironment().getProperty("os.name");
if(property.contains("Windows")){
return true;
}
return false;
}
}
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) {
String property = conditionContext.getEnvironment().getProperty("os.name");
if(property.contains("Linux")){
return true;
}
return false;
}
}
- @Condition注解结合@Bean使用,注解在方法上。当满足条件,创建相应实例并注入容器。
import com.michael.annotation.demo.POJO.Person;
import com.michael.annotation.demo.condition.LinuxCondition;
import com.michael.annotation.demo.condition.MacOSCondition;
import com.michael.annotation.demo.condition.WindowsCondition;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.*;
@Configuration
@ComponentScan(value = {"com.michael"},
excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {SpringBootApplication.class})
})
public class MyConfig {
@Lazy
@Bean
@Scope(value = "singleton")
public Person person(){
System.out.println("get");
return new Person("Steven", 11);
}
@Conditional(value = {MacOSCondition.class})
@Bean("Mac")
public Person person1(){
return new Person("Mac", 20);
}
@Conditional(value = {WindowsCondition.class})
@Bean("Windows")
public Person person2(){
return new Person("Windows", 20);
}
@Conditional(value = {LinuxCondition.class})
@Bean("Linux")
public Person person3(){
return new Person("Linux", 20);
}
}
import com.michael.annotation.demo.POJO.Person;
import com.michael.annotation.demo.configuration.MyConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import static java.lang.System.out;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
for(String name : applicationContext.getBeanDefinitionNames()){
out.println(name);
}
}
}
- 测试输出:
get
2020-03-20 11:47:15.369 INFO 10583 --- [ main] c.m.annotation.demo.DemoApplication : Started DemoApplication in 0.55 seconds (JVM running for 0.918)
get
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
myConfig
personService
person
Mac
从输出可以发现,因为当前操作系统为Mac OS X,所以对应的Bean被创建并且注入了容器。
-
当@Condition注解到类上,可以作用到类中的其他注解。
-
除了@Condition这个原生注解,Spring提供了一些组合注解给我们使用
- @ConditionalOnBean(仅仅在当前上下文中存在某个对象时,才会实例化一个Bean)
- @ConditionalOnClass(某个class位于类路径上,才会实例化一个Bean)
- @ConditionalOnExpression(当表达式为true的时候,才会实例化一个Bean)
- @ConditionalOnMissingBean(仅仅在当前上下文中不存在某个对象时,才会实例化一个Bean)
- @ConditionalOnMissingClass(某个class类路径上不存在的时候,才会实例化一个Bean)
- @ConditionalOnNotWebApplication(不是web应用)
- 等
- 代码演示使用@ConditionalOnBean:
import com.michael.annotation.demo.POJO.Person;
import com.michael.annotation.demo.condition.LinuxCondition;
import com.michael.annotation.demo.condition.MacOSCondition;
import com.michael.annotation.demo.condition.WindowsCondition;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.*;
@Configuration
@ComponentScan(value = {"com.michael"},
excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {SpringBootApplication.class})
})
public class MyConfig {
@ConditionalOnBean(name = {"myConfig"})
@Lazy
@Bean
@Scope(value = "singleton")
public Person person(){
System.out.println("get");
return new Person("Steven", 11);
}
@Conditional(value = {MacOSCondition.class})
@Bean("Mac")
public Person person1(){
return new Person("Mac", 20);
}
@Conditional(value = {WindowsCondition.class})
@Bean("Windows")
public Person person2(){
return new Person("Windows", 20);
}
@Conditional(value = {LinuxCondition.class})
@Bean("Linux")
public Person person3(){
return new Person("Linux", 20);
}
}
这里对person方法注解了@ConditionalOnBean(name = {“myConfig”})。
输出:
get
2020-03-20 15:38:13.329 INFO 11136 --- [ main] c.m.annotation.demo.DemoApplication : Started DemoApplication in 0.494 seconds (JVM running for 0.817)
get
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
myConfig
personService
person
Mac
把条件改@ConditionalOnBean(name = {“Mac”})
输出:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
myConfig
personService
Mac
对比两次输出,可以发现Bean注入容器的顺序是按照代码代码顺序的。