好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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

spring boot中的那些conditional

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

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

@conditional

下面其他的conditional注解均是语法糖,可以通过下面的方法自定义conditionalonxxx

conditional注解定义如下,接收实现condition接口的class数组。

?

1

2

3

public @interface conditional {

   class <? extends condition>[] value();

}

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

?

1

2

3

public interface condition {

   boolean matches(conditioncontext context, annotatedtypemetadata metadata);

}

通过操作系统进行 条件判断 ,从而进行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( "当前系统为:" + 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实例,则实例化一个备用电脑。

?

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是武士,使用套装进行战斗

?

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会设置为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

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

?

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适合面对较为复杂的情况,比如多个property的关联比较。这个例子也给了三种基本类型的条件判断,不过貌似均当成字符串就可以...

?

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

这个还没有想到应用场景,条件通过的条件是:1 对应的bean容器中只有一个 2.对应的bean有多个,但是已经制定了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

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

原文链接:https://segmentfault测试数据/a/1190000018831198

查看更多关于Spring Boot中的那些条件判断的实现方法的详细内容...

  阅读:12次