Spring Boot中的条件判断的介绍(附代码)

互联网 19-4-11

本篇文章给大家带来的内容是关于Spring Boot中的条件判断的介绍(附代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

Spring Boot中的那些Conditional

spring boot中为我们提供了丰富的Conditional来让我们得以非常方便的在项目中向容器中添加Bean。本文主要是对各个注解进行解释并辅以代码说明其用途。

所有ConditionalOnXXX的注解都可以放置在class或是method上,如果方式在class上,则会决定该class中所有的@Bean注解方法是否执行。

@Conditional

public @interface Conditional {     Class<? extends Condition>[] value(); }

而Condition接口只有一个matchs方法,返回是否匹配的结果。

public interface Condition {     boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata); }

通过操作系统进行条件判断,从而进行Bean配置。当Window时,实例化Bill的Person对象,当Linux时,实例化Linus的Person对象。

//LinuxCondition,为方便起见,去掉判断代码,直接返回true了 public class LinuxCondition implements Condition {     @Override     public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {         return true;     } }
//WindowsCondition,为方便起见,去掉判断代码,直接返回false了 public class WindowsCondition implements Condition {     @Override     public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata) {         return false;     } }
@Data @ToString @AllArgsConstructor @NoArgsConstructor public class Person {     private String name;     private Integer age; }
//配置类 @Configuration public class BeanConfig {      @Bean(name = "bill")     @Conditional({WindowsCondition.class})     public Person person1(){         return new Person("Bill Gates",62);     }      @Bean("linus")     @Conditional({LinuxCondition.class})     public Person person2(){         return new Person("Linus",48);     } }
public class AppTest {     AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class);      @Test     public void test(){         String osName = applicationContext.getEnvironment().getProperty("os.name");         System.out.println("当前系统为:" + osName);         Map<String, Person> map = applicationContext.getBeansOfType(Person.class);         System.out.println(map);     } }

输出的结果:

@ConditionalOnBean & @ConditionalOnMissingBean

这两个注解会对Bean容器中的Bean对象进行判断,使用的例子是配置的时候,如果发现如果没有Computer实例,则实例化一个备用电脑。

@Data @AllArgsConstructor @ToString public class Computer {     private String name; }
@Configuration public class BeanConfig {     @Bean(name = "notebookPC")     public Computer computer1(){         return new Computer("笔记本电脑");     }      @ConditionalOnMissingBean(Computer.class)     @Bean("reservePC")     public Computer computer2(){         return new Computer("备用电脑");     } }
public class TestApp {     AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class);     @Test     public void test1(){         Map<String,Computer> map = applicationContext.getBeansOfType(Computer.class);         System.out.println(map);     } }

修改BeanConfig,如果注释掉第一个@Bean,会实例化备用电脑,否则就不会实例化备用电脑

@ConditionalOnClass & @ConditionalOnMissingClass

public interface Fighter {     void fight(); } public class FighterA implements Fighter {     @Override     public void fight() {         System.out.println("使用光明套装");     } } public class FighterB implements Fighter {     @Override     public void fight() {         System.out.println("使用暗黑套装");     } }

Van是武士,使用套装进行战斗

@Data @AllArgsConstructor @NoArgsConstructor public class Van {     private Fighter fighter;     public void fight(){         fighter.fight();     } }

VanConfigA/B实例化武士

@Configuration @ConditionalOnClass({FighterA.class}) public class VanConfigA {     @Primary     @Bean     public Van vanA(){         return new Van(new FighterA());     } } @Configuration @ConditionalOnClass({FighterB.class}) public class VanConfigB {     @Bean     public Van vanB(){         return new Van(new FighterB());     } }

测试类,默认情况,如果套装AB都在类路径上,两套都会加载,A会设置为PRIMARY,如果在target class中将FightA.class删除,则只会加载套装B。

@SpringBootApplication public class TestApp implements CommandLineRunner {     @Autowired     private Van van;     public static void main(String[] args) {         SpringApplication.run(TestApp.class, args);     }     @Override     public void run(String... args) throws Exception {         //do something        van.fight();     } }

另外,尝试将两个VanConfigA/B合并,将注解ConditionalOnClass放到方法上,如果删除一个套装就会运行出错。

@ConditionalOnExpress

依据表达式进行条件判断,这个作用和@ConditionalOnProperty大部分情况可以通用,表达式更灵活一点,因为可以使用SpEL。例子中会判断properties中test.enabled的值进行判断。BeanConfig分别对布尔,字符串和数字三种类型进行判断。数字尝试了很多其他的方式均不行,比如直接使用==,貌似配置的属性都会当成字符串来处理。

@Data public class TestBean {     private String name; }
@Configuration @ConditionalOnExpression("#{${test.enabled:true} }") //@ConditionalOnExpression("'zz'.equalsIgnoreCase('${test.name2}')") //@ConditionalOnExpression("new Integer('${test.account}')==1") public class BeanConfig {     @Bean     public TestBean testBean(){         return new TestBean("我是美猴王");     } }
@SpringBootApplication public class TestAppCommand implements CommandLineRunner {     @Autowired     private TestBean testBean;      public static void main(String[] args) {         SpringApplication.run(TestAppCommand.class, args);     }      @Override     public void run(String... args) throws Exception {         System.out.println(testBean.getName());     } }

@ConditionalOnProperty

适合对单个Property进行条件判断,而上面的@ConditionalOnExpress适合面对较为复杂的情况,比如多个property的关联比较。这个例子也给了三种基本类型的条件判断,不过貌似均当成字符串就可以...

@Data @AllArgsConstructor @NoArgsConstructor public class TestBean {     private String name; }
@Configuration @ConditionalOnProperty(prefix = "test", name="enabled", havingValue = "true",matchIfMissing = false) //@ConditionalOnProperty(prefix = "test", name="account", havingValue = "1",matchIfMissing = false) //@ConditionalOnProperty(prefix = "test", name="name1", havingValue = "zz",matchIfMissing = false) public class BeanConfig {      @Bean     public TestBean testBean(){         return new TestBean("我是美猴王");     } }
@SpringBootApplication public class TestAppCommand implements CommandLineRunner {     @Autowired     private TestBean testBean;     public static void main(String[] args) {         SpringApplication.run(TestAppCommand.class, args);     }     @Override     public void run(String... args) throws Exception {         System.out.println(testBean.getName());      } }

@ConditionalOnJava

可以通过java的版本进行判断。

@Data public class TestBean { }
@Configuration @ConditionalOnJava(JavaVersion.EIGHT) public class BeanConfig {      @Bean     public TestBean testBean(){         return new TestBean();     } }
public class TestApp {     AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);     @Test     public void test(){         Map<String,TestBean> map = context.getBeansOfType(TestBean.class);         System.out.println(map);     } }

@ConditionalOnResource

通过指定的资源文件是否存在进行条件判断,比如判断ehcache.properties来决定是否自动装配ehcache组件。

@Data public class TestBean { }
@Configuration @ConditionalOnResource(resources = "classpath:application.yml") public class BeanConfig {      @Bean     public TestBean testBean(){         return new TestBean();     } }
public class TestApp {     AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);      @Test     public void test(){         Map<String,TestBean> map = context.getBeansOfType(TestBean.class);         System.out.println(map);     } }

@ConditionalOnSingleCandidate

这个还没有想到应用场景,条件通过的条件是:1 对应的bean容器中只有一个 2.对应的bean有多个,但是已经制定了PRIMARY。例子中,BeanB装配的时候需要看BeanA的装配情况,所以BeanBConfig要排在BeanAConfig之后.可以修改BeanAConfig,将@Primary注解去掉,或者把三个@Bean注解去掉,BeanB就不会实例化了。

@Data @AllArgsConstructor @NoArgsConstructor public class BeanA {     private String name; }
@Configuration public class BeanAConfig {      @Bean     @Primary     public BeanA bean1(){         return new BeanA("bean1");     }     @Bean(autowireCandidate = false)     public BeanA bean2(){         return new BeanA("bean2");     }     //@Bean(autowireCandidate = false)     public BeanA bean3(){         return new BeanA("bean3");     } }
@Data public class BeanB { }
@Configuration @AutoConfigureAfter(BeanAConfig.class) @ConditionalOnSingleCandidate(BeanA.class) public class BeanBConfig {      @Bean     public BeanB targetBean(){         return new BeanB();     } }
public class TestApp {     AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanAConfig.class, BeanBConfig.class);      @Test     public void test(){         Map<String,BeanA> map = context.getBeansOfType(BeanA.class);         System.out.println(map);         Map<String,BeanB> map2 = context.getBeansOfType(BeanB.class);         System.out.println(map2);     } }

@ConditionalOnNotWebApplication & @ConditionalOnWebApplication

判断当前环境是否是Web应用。

  1. 专栏
  2. 文章详情

沈子平 117

1 小时前发布

Spring Boot中的那些条件判断

  • java

19 次阅读 · 读完需要 31 分钟

end .post-topheader

0

Spring Boot中的那些Conditional

spring boot中为我们提供了丰富的Conditional来让我们得以非常方便的在项目中向容器中添加Bean。本文主要是对各个注解进行解释并辅以代码说明其用途。

所有ConditionalOnXXX的注解都可以放置在class或是method上,如果方式在class上,则会决定该class中所有的@Bean注解方法是否执行。

@Conditional

public @interface Conditional {     Class<? extends Condition>[] value(); }

而Condition接口只有一个matchs方法,返回是否匹配的结果。

public interface Condition {     boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata); }

通过操作系统进行条件判断,从而进行Bean配置。当Window时,实例化Bill的Person对象,当Linux时,实例化Linus的Person对象。

//LinuxCondition,为方便起见,去掉判断代码,直接返回true了 public class LinuxCondition implements Condition {     @Override     public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {         return true;     } }
//WindowsCondition,为方便起见,去掉判断代码,直接返回false了 public class WindowsCondition implements Condition {     @Override     public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata) {         return false;     } }
@Data @ToString @AllArgsConstructor @NoArgsConstructor public class Person {     private String name;     private Integer age; }
//配置类 @Configuration public class BeanConfig {      @Bean(name = "bill")     @Conditional({WindowsCondition.class})     public Person person1(){         return new Person("Bill Gates",62);     }      @Bean("linus")     @Conditional({LinuxCondition.class})     public Person person2(){         return new Person("Linus",48);     } }
public class AppTest {     AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class);      @Test     public void test(){         String osName = applicationContext.getEnvironment().getProperty("os.name");         System.out.println("当前系统为:" + osName);         Map<String, Person> map = applicationContext.getBeansOfType(Person.class);         System.out.println(map);     } }

输出的结果:

@ConditionalOnBean & @ConditionalOnMissingBean

这两个注解会对Bean容器中的Bean对象进行判断,使用的例子是配置的时候,如果发现如果没有Computer实例,则实例化一个备用电脑。

@Data @AllArgsConstructor @ToString public class Computer {     private String name; }
@Configuration public class BeanConfig {     @Bean(name = "notebookPC")     public Computer computer1(){         return new Computer("笔记本电脑");     }      @ConditionalOnMissingBean(Computer.class)     @Bean("reservePC")     public Computer computer2(){         return new Computer("备用电脑");     } }
public class TestApp {     AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class);     @Test     public void test1(){         Map<String,Computer> map = applicationContext.getBeansOfType(Computer.class);         System.out.println(map);     } }

修改BeanConfig,如果注释掉第一个@Bean,会实例化备用电脑,否则就不会实例化备用电脑

@ConditionalOnClass & @ConditionalOnMissingClass

public interface Fighter {     void fight(); } public class FighterA implements Fighter {     @Override     public void fight() {         System.out.println("使用光明套装");     } } public class FighterB implements Fighter {     @Override     public void fight() {         System.out.println("使用暗黑套装");     } }

Van是武士,使用套装进行战斗

@Data @AllArgsConstructor @NoArgsConstructor public class Van {     private Fighter fighter;     public void fight(){         fighter.fight();     } }

VanConfigA/B实例化武士

@Configuration @ConditionalOnClass({FighterA.class}) public class VanConfigA {     @Primary     @Bean     public Van vanA(){         return new Van(new FighterA());     } } @Configuration @ConditionalOnClass({FighterB.class}) public class VanConfigB {     @Bean     public Van vanB(){         return new Van(new FighterB());     } }

测试类,默认情况,如果套装AB都在类路径上,两套都会加载,A会设置为PRIMARY,如果在target class中将FightA.class删除,则只会加载套装B。

@SpringBootApplication public class TestApp implements CommandLineRunner {     @Autowired     private Van van;     public static void main(String[] args) {         SpringApplication.run(TestApp.class, args);     }     @Override     public void run(String... args) throws Exception {         //do something        van.fight();     } }

另外,尝试将两个VanConfigA/B合并,将注解ConditionalOnClass放到方法上,如果删除一个套装就会运行出错。

@ConditionalOnExpress

依据表达式进行条件判断,这个作用和@ConditionalOnProperty大部分情况可以通用,表达式更灵活一点,因为可以使用SpEL。例子中会判断properties中test.enabled的值进行判断。BeanConfig分别对布尔,字符串和数字三种类型进行判断。数字尝试了很多其他的方式均不行,比如直接使用==,貌似配置的属性都会当成字符串来处理。

@Data public class TestBean {     private String name; }
@Configuration @ConditionalOnExpression("#{${test.enabled:true} }") //@ConditionalOnExpression("'zz'.equalsIgnoreCase('${test.name2}')") //@ConditionalOnExpression("new Integer('${test.account}')==1") public class BeanConfig {     @Bean     public TestBean testBean(){         return new TestBean("我是美猴王");     } }
@SpringBootApplication public class TestAppCommand implements CommandLineRunner {     @Autowired     private TestBean testBean;      public static void main(String[] args) {         SpringApplication.run(TestAppCommand.class, args);     }      @Override     public void run(String... args) throws Exception {         System.out.println(testBean.getName());     } }

@ConditionalOnProperty

适合对单个Property进行条件判断,而上面的@ConditionalOnExpress适合面对较为复杂的情况,比如多个property的关联比较。这个例子也给了三种基本类型的条件判断,不过貌似均当成字符串就可以...

@Data @AllArgsConstructor @NoArgsConstructor public class TestBean {     private String name; }
@Configuration @ConditionalOnProperty(prefix = "test", name="enabled", havingValue = "true",matchIfMissing = false) //@ConditionalOnProperty(prefix = "test", name="account", havingValue = "1",matchIfMissing = false) //@ConditionalOnProperty(prefix = "test", name="name1", havingValue = "zz",matchIfMissing = false) public class BeanConfig {      @Bean     public TestBean testBean(){         return new TestBean("我是美猴王");     } }
@SpringBootApplication public class TestAppCommand implements CommandLineRunner {     @Autowired     private TestBean testBean;     public static void main(String[] args) {         SpringApplication.run(TestAppCommand.class, args);     }     @Override     public void run(String... args) throws Exception {         System.out.println(testBean.getName());      } }

@ConditionalOnJava

可以通过java的版本进行判断。

@Data public class TestBean { }
@Configuration @ConditionalOnJava(JavaVersion.EIGHT) public class BeanConfig {      @Bean     public TestBean testBean(){         return new TestBean();     } }
public class TestApp {     AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);     @Test     public void test(){         Map<String,TestBean> map = context.getBeansOfType(TestBean.class);         System.out.println(map);     } }

@ConditionalOnResource

通过指定的资源文件是否存在进行条件判断,比如判断ehcache.properties来决定是否自动装配ehcache组件。

@Data public class TestBean { }
@Configuration @ConditionalOnResource(resources = "classpath:application.yml") public class BeanConfig {      @Bean     public TestBean testBean(){         return new TestBean();     } }
public class TestApp {     AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);      @Test     public void test(){         Map<String,TestBean> map = context.getBeansOfType(TestBean.class);         System.out.println(map);     } }

@ConditionalOnSingleCandidate

这个还没有想到应用场景,条件通过的条件是:1 对应的bean容器中只有一个 2.对应的bean有多个,但是已经制定了PRIMARY。例子中,BeanB装配的时候需要看BeanA的装配情况,所以BeanBConfig要排在BeanAConfig之后.可以修改BeanAConfig,将@Primary注解去掉,或者把三个@Bean注解去掉,BeanB就不会实例化了。

@Data @AllArgsConstructor @NoArgsConstructor public class BeanA {     private String name; }
@Configuration public class BeanAConfig {      @Bean     @Primary     public BeanA bean1(){         return new BeanA("bean1");     }     @Bean(autowireCandidate = false)     public BeanA bean2(){         return new BeanA("bean2");     }     //@Bean(autowireCandidate = false)     public BeanA bean3(){         return new BeanA("bean3");     } }
@Data public class BeanB { }
@Configuration @AutoConfigureAfter(BeanAConfig.class) @ConditionalOnSingleCandidate(BeanA.class) public class BeanBConfig {      @Bean     public BeanB targetBean(){         return new BeanB();     } }
public class TestApp {     AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanAConfig.class, BeanBConfig.class);      @Test     public void test(){         Map<String,BeanA> map = context.getBeansOfType(BeanA.class);         System.out.println(map);         Map<String,BeanB> map2 = context.getBeansOfType(BeanB.class);         System.out.println(map2);     } }

@ConditionalOnNotWebApplication & @ConditionalOnWebApplication

判断当前环境是否是Web应用。

    • 举报

你可能感兴趣的

评论

默认排序 时间排序

载入中...

显示更多评论

以上就是Spring Boot中的条件判断的介绍(附代码)的详细内容,更多内容请关注技术你好其它相关文章!

来源链接:
免责声明:
1.资讯内容不构成投资建议,投资者应独立决策并自行承担风险
2.本文版权归属原作所有,仅代表作者本人观点,不代表本站的观点或立场
标签: java
上一篇:php获取远程图片并下载保存到本地的方法分析 下一篇:Java中如何将数组反转?Java数组反转的2种方法(代码示例)

相关资讯