spring boot中的那些conditional
spring boot中為我們提供了豐富的conditional來讓我們得以非常方便的在項目中向容器中添加bean。本文主要是對各個注解進行解釋并輔以代碼說明其用途。
所有conditionalonxxx的注解都可以放置在class或是method上,如果方式在class上,則會決定該class中所有的@bean注解方法是否執(zhí)行。
@conditional
下面其他的conditional注解均是語法糖,可以通過下面的方法自定義conditionalonxxx
conditional注解定義如下,接收實現(xiàn)condition接口的class數(shù)組。
1
2
3
|
public @interface conditional { class <? extends condition>[] value(); } |
而condition接口只有一個matchs方法,返回是否匹配的結(jié)果。
1
2
3
|
public interface condition { boolean matches(conditioncontext context, annotatedtypemetadata metadata); } |
通過操作系統(tǒng)進行條件判斷,從而進行bean配置。當window時,實例化bill的person對象,當linux時,實例化linus的person對象。
1
2
3
4
5
6
7
|
//linuxcondition,為方便起見,去掉判斷代碼,直接返回true了 public class linuxcondition implements condition { @override public boolean matches(conditioncontext conditioncontext, annotatedtypemetadata annotatedtypemetadata) { return true ; } } |
1
2
3
4
5
6
7
8
|
//windowscondition,為方便起見,去掉判斷代碼,直接返回false了 public class windowscondition implements condition { @override public boolean matches(conditioncontext conditioncontext, annotatedtypemetadata metadata) { return false ; } } @data |
1
2
3
4
5
6
7
|
@tostring @allargsconstructor @noargsconstructor public class person { private string name; private integer age; } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
//配置類 @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 ); } } |
1
2
3
4
5
6
7
8
9
10
11
|
public class apptest { annotationconfigapplicationcontext applicationcontext = new annotationconfigapplicationcontext(beanconfig. class ); @test public void test(){ string osname = applicationcontext.getenvironment().getproperty( "os.name" ); system.out.println( "當前系統(tǒng)為:" + osname); map<string, person> map = applicationcontext.getbeansoftype(person. class ); system.out.println(map); } } |
輸出的結(jié)果:
當前系統(tǒng)為:mac os x
{linus=person(name=linus, age=48)}
@conditionalonbean & @conditionalonmissingbean
這兩個注解會對bean容器中的bean對象進行判斷,使用的例子是配置的時候,如果發(fā)現(xiàn)如果沒有computer實例,則實例化一個備用電腦。
1
2
3
4
5
6
|
@data @allargsconstructor @tostring public class computer { private string name; } |
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@configuration public class beanconfig { @bean (name = "notebookpc" ) public computer computer1(){ return new computer( "筆記本電腦" ); } @conditionalonmissingbean (computer. class ) @bean ( "reservepc" ) public computer computer2(){ return new computer( "備用電腦" ); } } |
1
2
3
4
5
6
7
8
|
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時,使用的就是這種方式。
例子是兩套盔甲a(光明套裝)和b(暗黑套裝),如果a不在則配置b。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
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是武士,使用套裝進行戰(zhàn)斗
1
2
3
4
5
6
7
8
9
|
@data @allargsconstructor @noargsconstructor public class van { private fighter fighter; public void fight(){ fighter.fight(); } } |
vanconfiga/b實例化武士
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
@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會設(shè)置為primary,如果在target class中將fighta.class刪除,則只會加載套裝b。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@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
依據(jù)表達式進行條件判斷,這個作用和@conditionalonproperty大部分情況可以通用,表達式更靈活一點,因為可以使用spel。例子中會判斷properties中test.enabled的值進行判斷。beanconfig分別對布爾,字符串和數(shù)字三種類型進行判斷。數(shù)字嘗試了很多其他的方式均不行,比如直接使用==,貌似配置的屬性都會當成字符串來處理。
1
2
3
4
|
@data public class testbean { private string name; } |
1
2
3
4
5
6
7
8
9
10
|
@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( "我是美猴王" ); } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
@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適合面對較為復(fù)雜的情況,比如多個property的關(guān)聯(lián)比較。這個例子也給了三種基本類型的條件判斷,不過貌似均當成字符串就可以...
1
2
3
4
5
6
|
@data @allargsconstructor @noargsconstructor public class testbean { private string name; } |
1
2
3
4
5
6
7
8
9
10
11
|
@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( "我是美猴王" ); } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@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的版本進行判斷。
1
2
3
|
@data public class testbean { } |
1
2
3
4
5
6
7
8
9
|
@configuration @conditionalonjava (javaversion.eight) public class beanconfig { @bean public testbean testbean(){ return new testbean(); } } |
1
2
3
4
5
6
7
8
|
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組件。
1
2
3
|
@data public class testbean { } |
1
2
3
4
5
6
7
8
9
|
@configuration @conditionalonresource (resources = "classpath:application.yml" ) public class beanconfig { @bean public testbean testbean(){ return new testbean(); } } |
1
2
3
4
5
6
7
8
9
|
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
這個還沒有想到應(yīng)用場景,條件通過的條件是:1 對應(yīng)的bean容器中只有一個 2.對應(yīng)的bean有多個,但是已經(jīng)制定了primary。例子中,beanb裝配的時候需要看beana的裝配情況,所以beanbconfig要排在beanaconfig之后.可以修改beanaconfig,將@primary注解去掉,或者把三個@bean注解去掉,beanb就不會實例化了。
1
2
3
4
5
6
|
@data @allargsconstructor @noargsconstructor public class beana { private string name; } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
@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" ); } } |
1
2
3
|
@data public class beanb { } |
1
2
3
4
5
6
7
8
9
10
|
@configuration @autoconfigureafter (beanaconfig. class ) @conditionalonsinglecandidate (beana. class ) public class beanbconfig { @bean public beanb targetbean(){ return new beanb(); } } |
1
2
3
4
5
6
7
8
9
10
11
|
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
判斷當前環(huán)境是否是web應(yīng)用。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持服務(wù)器之家。
原文鏈接:https://segmentfault.com/a/1190000018831198