springboot根據不同的條件創建bean,動態創建bean,@Conditional注解使用


 

 

這個需求應該也比較常見,在不同的條件下創建不同的bean,具體場景很多,能看到這篇的肯定懂我的意思。

倘若不了解spring4.X新加入的@Conditional注解的話,要實現不同條件創建不同的bean還是比較麻煩的,可能需要硬編碼一些東西做if判斷。那么現在有個@Conditional注解后,事情就簡單多了。用法很簡單,直接上代碼。

新建一個springboot項目,添加一個Configuration標注的類,我們通過不同的條件表達式來創建bean。

 

  1.  
    package com.tianyalei.condition;
  2.  
     
  3.  
    import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
  4.  
    import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
  5.  
    import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
  6.  
    import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
  7.  
    import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  8.  
    import org.springframework.context.annotation.Bean;
  9.  
    import org.springframework.context.annotation.Conditional;
  10.  
    import org.springframework.context.annotation.Configuration;
  11.  
     
  12.  
    /**
  13.  
    * Created by wuweifeng on 2017/10/11.
  14.  
    */
  15.  
    @Configuration
  16.  
    public class Config {
  17.  
     
  18.  
    @Conditional(MyCondition.class)
  19.  
    @Bean
  20.  
    public String condition() {
  21.  
    System.err.println( "自定義的condition的match方法返回值為true時,才會進入該方法創建bean");
  22.  
    return "";
  23.  
    }
  24.  
     
  25.  
    /**
  26.  
    * 該Abc class位於類路徑上時
  27.  
    */
  28.  
    @ConditionalOnClass(Abc.class)
  29.  
    @Bean
  30.  
    public String abc() {
  31.  
    System.err.println( "ConditionalOnClass true");
  32.  
    return "";
  33.  
    }
  34.  
     
  35.  
    // @ConditionalOnClass(Abc.class)
  36.  
    // @Bean
  37.  
    // public Abc newAbc() {
  38.  
    // System.err.println("ConditionalOnClass true");
  39.  
    // return new Abc();
  40.  
    // }
  41.  
     
  42.  
    /**
  43.  
    * 存在Abc類的實例時
  44.  
    */
  45.  
    @ConditionalOnBean(Abc.class)
  46.  
    @Bean
  47.  
    public String bean() {
  48.  
    System.err.println( "ConditionalOnBean is exist");
  49.  
    return "";
  50.  
    }
  51.  
     
  52.  
    @ConditionalOnMissingBean(Abc.class)
  53.  
    @Bean
  54.  
    public String missBean() {
  55.  
    System.err.println( "ConditionalOnBean is missing");
  56.  
    return "";
  57.  
    }
  58.  
     
  59.  
    /**
  60.  
    * 表達式為true時
  61.  
    */
  62.  
    @ConditionalOnExpression(value = "true")
  63.  
    @Bean
  64.  
    public String expresssion() {
  65.  
    System.err.println( "expresssion is true");
  66.  
    return "";
  67.  
    }
  68.  
     
  69.  
    /**
  70.  
    * 配置文件屬性是否為true
  71.  
    */
  72.  
    @ConditionalOnProperty(
  73.  
    value = { "abc.property"},
  74.  
    matchIfMissing = false)
  75.  
    @Bean
  76.  
    public String property() {
  77.  
    System.err.println( "property is true");
  78.  
    return "";
  79.  
    }
  80.  
    }

 

這里面有個空類Abc.class,你可以就創建個叫Abc的類,里面是空的就行。

 

  1.  
    import org.springframework.context.annotation.Condition;
  2.  
    import org.springframework.context.annotation.ConditionContext;
  3.  
    import org.springframework.core.type.AnnotatedTypeMetadata;
  4.  
     
  5.  
    /**
  6.  
    * Created by wuweifeng on 2017/10/11.
  7.  
    */
  8.  
    public class MyCondition implements Condition {
  9.  
    @Override
  10.  
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
  11.  
    //判斷當前系統是Mac,Windows,Linux
  12.  
    return conditionContext.getEnvironment().getProperty("os.name").contains("Mac");
  13.  
    }
  14.  
    }

 


@Conditional(MyCondition.class)
這句代碼可以標注在類上面,表示該類下面的所有@Bean都會啟用配置
也可以標注在方法上面,只是對該方法啟用配置


除了自己自定義Condition之外,Spring還提供了很多Condition給我們用
@ConditionalOnBean(僅僅在當前上下文中存在某個對象時,才會實例化一個Bean)
@ConditionalOnClass(某個class位於類路徑上,才會實例化一個Bean)
@ConditionalOnExpression(當表達式為true的時候,才會實例化一個Bean)
@ConditionalOnMissingBean(僅僅在當前上下文中不存在某個對象時,才會實例化一個Bean)
@ConditionalOnMissingClass(某個class類路徑上不存在的時候,才會實例化一個Bean)
@ConditionalOnNotWebApplication(不是web應用)

以上是一些常用的注解,其實就是條件判斷,如果為true了就創建Bean,為false就不創建,就這么簡單。

這些注解里的條件可以是多個,也可以賦默認值,也可以標注在類上,如果標注在類上,則對類里的所有@Bean方法都生效。

其中@ConditionalOnProperty是指在application.yml里配置的屬性是否為true,其他的幾個都是對class的判斷。

我在配置里加上abc.property = true這個配置就可以測試上面的代碼了。

然后再來一個對類進行多個條件標注的例子:

 

  1.  
    package com.tianyalei.condition;
  2.  
     
  3.  
    import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
  4.  
    import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
  5.  
    import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  6.  
    import org.springframework.context.annotation.Bean;
  7.  
    import org.springframework.context.annotation.Configuration;
  8.  
     
  9.  
    /**
  10.  
    * Created by wuweifeng on 2017/10/11.
  11.  
    */
  12.  
    @Configuration
  13.  
    @ConditionalOnProperty(
  14.  
    value = { "abc.property"},
  15.  
    matchIfMissing = false
  16.  
    )
  17.  
    @ConditionalOnClass(Abc.class)
  18.  
    public class Multi {
  19.  
    @Bean
  20.  
    @ConditionalOnMissingBean({Abc.class})
  21.  
    public String check() {
  22.  
    System.err.println( "multi check");
  23.  
    return "check";
  24.  
    }
  25.  
    }
OK,代碼很簡單,運行看看結果

 

可能上面的那些你用的地方不常見,那我來舉一個我正在使用的例子。我的應用是基於SpringCloud的,在線上部署時有eureka來做注冊中心,而在本地環境下,我的應用是單機的,不需要eureka,但是代碼里已經引入了eureka了,每次啟動就會自動去連接eureka,然后控制台就開始報錯。雖然不影響功能,但是看着一直不停的報錯也是不順眼。

那么我就可以使用Condition注解來解決它。

 

  1.  
    /**
  2.  
    * @author wuweifeng wrote on 2017/11/25.
  3.  
    * 根據部署環境動態決定是否啟用eureka
  4.  
    */
  5.  
    @Component
  6.  
    @ConditionalOnProperty(value = "open.eureka")
  7.  
    @EnableDiscoveryClient
  8.  
    public class JudgeEnableDiscoveryClient {
  9.  
    }
我把EnableDiscoveryClient這個注解單獨放個類里,里面什么也不寫,條件就是application.yml里配置的open.eureka
如果我只想讓線上的環境開啟eureka,那么我就在application-prod.yml里配上open.eureka=true,其他的yml什么也不寫就行了。這樣本地啟動時就相當於沒有開啟EnableDiscoveryClient。

 

使用場景還是蠻多的,具體的看情況,但是需要記住有這么個注解,以便不時之需。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM