1. <output id="hzk7v"><pre id="hzk7v"><address id="hzk7v"></address></pre></output>
      <output id="hzk7v"></output>
    2. <nav id="hzk7v"><i id="hzk7v"><em id="hzk7v"></em></i></nav>
    3. <listing id="hzk7v"><delect id="hzk7v"><em id="hzk7v"></em></delect></listing>

      Spring Boot中的那些条件判断的实现方法

       更新时间£º2019年04月12日 11:26:34   作者£º沈子平   我要评论

      这篇文章主要介绍了Spring Boot中的那些条件判断的实现方法£¬文中通过示例代码介绍的非常详细£¬对大家的学习或者工作具有一定的参考学习价值£¬需要的朋友们下面随?#21028;?#32534;来一起学习学习吧

      Spring Boot中的那些Conditional

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

      所有ConditionalOnXXX的注解都可以放置在class或是method上£¬如果方式在class上£¬则会决定该class中所有的@Bean注解方法是否执?#23567;?/p>

      @Conditional

      下面其他的Conditional注解均是语法糖£¬可以通过下面的方法自定义ConditionalOnXXX

      Conditional注解定义如下£¬接收实现Condition接口的class数组¡£

      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);
        }
      }
      
      

      输出的结果£º

      当前系统为£ºMac OS X
      {linus=Person(name=Linus, age=48)}

      @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("?#22987;?#26412;电脑");
        }
      
        @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

      这个注解会判断类路径上是否有指定的类£¬一开始看到的时候比较困惑£¬类路径上如果没有指定的class,那编译也通过不了啊...这个主要用于集成相同功能的第三方组件时用£¬只要类路径上有该组件的类£¬就进行自动配置£¬比如spring boot web在自动配置视图组件时£¬是用Velocity£¬还是Thymeleaf,或是freemaker时£¬使用的就是这种方式¡£

      例子是?#25945;?#30420;甲A(光明套装)和B(暗黑套装)£¬如果A不在则配置B¡£

      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都在类路径上£¬?#25945;?#37117;会加载£¬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?#30452;?#23545;?#32423;û£?#23383;符串和数字三种类型进行判断¡£数字尝试了很多其他的方式均不行£¬比如直接使用==£¬?#33756;?#37197;置的属性都会当成字符串来处理¡£

      @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的关联比较¡£这个例子也给了三种基本类型的条件判断£¬不过?#33756;?#22343;当成字符串就可以...

      @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

      这个还没有想?#25509;?#29992;场景£¬条件通过的条件是£º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应用¡£

      以上就是本文的全部内容£¬希望对大家的学习有所帮助£¬也希望大家多多支持脚本之家¡£

      相关文章

      最新评论

      3dÊÔ»úºÅÖвÊÍø

        1. <output id="hzk7v"><pre id="hzk7v"><address id="hzk7v"></address></pre></output>
          <output id="hzk7v"></output>
        2. <nav id="hzk7v"><i id="hzk7v"><em id="hzk7v"></em></i></nav>
        3. <listing id="hzk7v"><delect id="hzk7v"><em id="hzk7v"></em></delect></listing>

            1. <output id="hzk7v"><pre id="hzk7v"><address id="hzk7v"></address></pre></output>
              <output id="hzk7v"></output>
            2. <nav id="hzk7v"><i id="hzk7v"><em id="hzk7v"></em></i></nav>
            3. <listing id="hzk7v"><delect id="hzk7v"><em id="hzk7v"></em></delect></listing>