首頁  >  文章  >  Java  >  Spring Boot中的條件判斷的介紹(附程式碼)

Spring Boot中的條件判斷的介紹(附程式碼)

不言
不言轉載
2019-04-11 13:14:083560瀏覽

這篇文章帶給大家的內容是關於Spring Boot中的條件判斷的介紹(附程式碼),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

Spring Boot中的那些Conditional

spring boot中為我們提供了豐富的Conditional來讓我們得以非常方便的在專案中向容器中添加Bean。本文主要是將各個註解解釋並輔以程式碼說明其用途。

所有ConditionalOnXXX的註解都可以放置在class或是method上,如果方式在class上,則會決定該class中所有的@Bean註解方法是否執行。

@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> map = applicationContext.getBeansOfType(Person.class);
        System.out.println(map);
    }
}</string>

輸出的結果:

目前系統為: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("笔记本电脑");
    }

    @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> map = applicationContext.getBeansOfType(Computer.class);
        System.out.println(map);
    }
}</string>

修改BeanConfig,如果註解掉第一個@Bean,會實例化備用電腦,否則就不會實例化備用電腦

@ConditionalOnClass & @ConditionalOnMissingClass

這個註解會判斷類路徑上是否有指定的類,一開始看到的時候比較困惑,類路徑上如果沒有指定的class,那編譯也通過不了啊...這個主要用於集成相同功能的第三方元件時用,只要類別路徑上有該元件的類別,就進行自動配置,例如spring boot web在自動配置視圖元件時,是用Velocity,還是Thymeleaf,或是freemaker時,使用的就是這種方式。
例子是兩組盔甲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都在類別路徑上,兩套都會載入,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> map = context.getBeansOfType(TestBean.class);
        System.out.println(map);
    }
}</string>

@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> map = context.getBeansOfType(TestBean.class);
        System.out.println(map);
    }
}</string>

@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> map = context.getBeansOfType(BeanA.class);
        System.out.println(map);
        Map<string> map2 = context.getBeansOfType(BeanB.class);
        System.out.println(map2);
    }
}</string></string>

@ConditionalOnNotWebApplication & @ConditionalOnWebApplication

判斷目前環境是否為Web應用程式。







#################################

117                                                                                                                                                

##                                                                                                                                             
  • Spring Boot中的條件判斷的介紹(附程式碼)

###                                                                   ####                                            ######Spring Boot##########################################################################)                                                                                 java###### #          19 次閱讀                                                 ·                                                 時所學。                                                                                          #################



                           0#                        




##                        

#                        

#                        

#                        

#                        

# ############Spring Boot中的那些Conditional#############spring boot中為我們提供了豐富的Conditional來讓我們得以非常方便的在專案中在容器中新增Bean。本文主要是將各個註解解釋並輔以程式碼說明其用途。 ######所有ConditionalOnXXX的註解都可以放置在class或是method上,如果方式在class上,則會決定該class中所有的@Bean註解方法是否執行。 ######@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> map = applicationContext.getBeansOfType(Person.class);
        System.out.println(map);
    }
}</string>
###輸出的結果:######目前系統為: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("笔记本电脑");
    }

    @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> map = applicationContext.getBeansOfType(Computer.class);
        System.out.println(map);
    }
}</string>
###修改BeanConfig,如果註解掉第一個@Bean,會實例化備用電腦,否則就不會實例化備用電腦######@ConditionalOnClass & @ConditionalOnMissingClass######這個註解會判斷類路徑上是否有指定的類,一開始看到的時候比較困惑,類路徑上如果沒有指定的class,那編譯也通過不了啊...這個主要用於集成相同功能的第三方元件時用,只要類別路徑上有該元件的類別,就進行自動配置,例如spring boot web在自動配置視圖元件時,是用Velocity,還是Thymeleaf,或是freemaker時,使用的就是這種方式。 ###例子是兩組盔甲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都在類別路徑上,兩套都會載入,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> map = context.getBeansOfType(TestBean.class);
        System.out.println(map);
    }
}</string>
###@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> map = context.getBeansOfType(TestBean.class);
        System.out.println(map);
    }
}</string>

@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> map = context.getBeansOfType(BeanA.class);
        System.out.println(map);
        Map<string> map2 = context.getBeansOfType(BeanB.class);
        System.out.println(map2);
    }
}</string></string>

@ConditionalOnNotWebApplication & @ConditionalOnWebApplication

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

  • Spring Boot中的條件判斷的介紹(附程式碼)


你可能感兴趣的



评论                                                    



载入中...

显示更多评论


以上是Spring Boot中的條件判斷的介紹(附程式碼)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除