本篇文章给人人带来的内容是关于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, 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("笔记本电脑"); } @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时,运用的就是这类体式格局。
例子是两套盔甲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,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
这个还没有想到运用场景,前提经由过程的前提是: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运用。
- 专栏
- 文章概况
1 小时前宣布
Spring Boot中的那些前提推断
19 次浏览 · 读完须要 31 分钟
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, 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("笔记本电脑"); } @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时,运用的就是这类体式格局。
例子是两套盔甲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,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
这个还没有想到运用场景,前提经由过程的前提是: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运用。
赞 | 0 珍藏 | 0
你能够感兴趣的
批评
默许排序 时候排序
载入中...
显现更多批评
宣布批评
以上就是Spring Boot中的前提推断的引见(附代码)的细致内容,更多请关注ki4网别的相干文章!