学习了profile bean之后,发现有的时候bean还是有根据环境来选择的余地的,那么假设我们希望某个bean只有当另外某个特定的bean也声明了之后才会创建。我们还可能要求只有某个特定的环境变量设置之后,才会创建某个bean。

在Spring 4之前,很难实现这种级别的条件化配置,但是Spring 4引入了一个新的@Conditional注解,它可以用到带有@Bean注解的方法上。如果给定的条件计算结果为true,就会创建这个bean,否则的话,这个bean会被忽略。

今天就来学习下 条件化的Bean。

创建方法是在方或者类上 添加一个@Conditional(xxx.class)  xxx.class表示一个逻辑性的内容,当满足需求的时候返回true这样一来这个@Bean就会被创建,反之就不创建

 @Bean
@Conditional(XXX.class)

这样一来,跟profile还是有点相似的,但是比他要强大的多的多。。。我们看Profile源码,你会发现Profile也添加了@Conditional,代码如下:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@Conditional({ProfileCondition.class})
public @interface Profile {
String[] value();
}

这个时候在查看下ProfileCondition.class

class ProfileCondition implements Condition {
ProfileCondition() {
}
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
if(context.getEnvironment() != null) {
MultiValueMap attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
if(attrs != null) {
Iterator var4 = ((List)attrs.get("value")).iterator();
Object value;
do {
if(!var4.hasNext()) {
return false;
}
value = var4.next();
} while(!context.getEnvironment().acceptsProfiles((String[])((String[])value))); return true;
}
}
return true;
}
}

这个时候我们会发现 有一个接口 Condition,之所以那么牛逼 估计全靠这个吧,看一下源码:

public interface Condition {
boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2);
}

有了ConditionContext,我们可以做到如下几点:

  • 借助getRegistry()返回的BeanDefinitionRegistry检查bean定义;
  • 借助getBeanFactory()返回的ConfigurableListableBeanFactory检查bean是
  • 否存在,甚至探查bean的属性;
  • 借助getEnvironment()返回的Environment检查环境变量是否存在以及它的值是
  • 什么;
  • 读取并探查getResourceLoader()返回的ResourceLoader所加载的资源;
  • 借助getClassLoader()返回的ClassLoader加载并检查类是否存在。

有了AnnotatedTypeMetadata则能够让我们检查带有@Bean注解的方法上还有什么其他的注解。

下面就以例子来说明:

假设有两个赏金猎人,一个高级的,一个初级的,他们各种会根据各自的赏金面板的消息(即Condition接口的实现类),决定是否去开始猎杀目标,下面先创造猎人接口以及两个猎人

public interface BountyHunter {

    void BeginHuntAndKill();
}

高级赏金猎人

public class SeniorBountyHunter implements BountyHunter {

    public void BeginHuntAndKill() {
System.out.println("我是高级赏金猎人哇哈哈哈,现在已有任务发布,我可以去做任务了!");
}
}

初级赏金猎人

public class PrimaryBountyHunter implements BountyHunter {

    public void BeginHuntAndKill() {
System.out.println("我是初级赏金猎人乌卡卡卡,现在已有任务发布,我可以去做任务了!");
}
}

然后分别再创建 各自的任务面板

高级任务

public class SeniorBounty implements Condition {

    public boolean matches(ConditionContext conditionContext,
AnnotatedTypeMetadata annotatedTypeMetadata) {
/**
* 各种自己想要的验证,然后根据结果来返回 一个boole值
*/
if (conditionContext.getEnvironment().acceptsProfiles("task")) {
return true;
} else {
return false;
}
}
}

初级任务

public class PrimaryBounty implements Condition {

    public boolean matches(ConditionContext conditionContext,
AnnotatedTypeMetadata annotatedTypeMetadata) {
/**
* 各种自己想要的验证,然后根据结果来返回 一个boole值
*/ if (conditionContext.getEnvironment().acceptsProfiles("task")) {
return true;
} else {
return false;
}
}
}

任务有了,人物也有了,下面就是需要一个人大喊一下:有新的任务发布了,赶紧去看啊!!

也就是Bean配置类

@Configuration
public class TaskConfig { @Bean
@Conditional(PrimaryBounty.class)
public BountyHunter ThePrimaryBountyHunter() {
return new PrimaryBountyHunter();
} @Bean
@Conditional(SeniorBounty.class)
public BountyHunter TheSeniorBountyHunter() {
return new SeniorBountyHunter();
}
}

现在有人通知了,让我们看一下是否有人领任务,开始去猎杀!

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TaskConfig.class)
@ActiveProfiles("task")
public class TaskBegin { @Autowired
SeniorBountyHunter seniorBountyHunter; @Autowired
PrimaryBountyHunter primaryBountyHunter; @Test
public void TaskLog() {
if (primaryBountyHunter != null) {
primaryBountyHunter.BeginHuntAndKill();
}
if (seniorBountyHunter != null) {
seniorBountyHunter.BeginHuntAndKill();
}
}
}

这边我们是根据Profile来测试的,根据这个判断任务是否满足,当然我们也可以不根据配置环境,我们可以根据任务的的属性是否跟猎人相匹配(即 可以根据 @Conditional(xxx.class) xxx.class 类中的判断,该Bean是否有我们需要的属性 )

测试结果

以上就是条件化的bean配置 简单小例子,如有错误,请指出,谢谢~

代码:https://github.com/eoooxy/springinaction test下 的com.bean.condition中

SpringInAction--条件化的Bean的更多相关文章

  1. 第3章—高级装配—条件化的Bean

    条件化的Bean 通过活动的profile,我们可以获得不同的Bean.Spring 4提供了一个更通用的基于条件的Bean的创建方式,即使用@Conditional注解. @Conditional根 ...

  2. 002Conditional条件化创建bean

    01.条件化配置bean @Bean @Conditional(MagicExistsCondition.class)---->条件化创建bean public MagicBean magicB ...

  3. Spring入门(六):条件化的bean

    1. 概念 默认情况下,Spring中定义的bean在应用程序启动时会全部装配,不管当前运行的是哪个环境(Dev,QA或者Prod),也不管当前运行的是什么系统(Windows或者Linux),但有些 ...

  4. (二)spring 高级装配-Condition -条件化的bean

    Condition:满足某个特定条件的情况下创建bean 条件化配置bean: a:@Conditional 指定一个class ,它指明了通过条件对比的类.如果没有指定class则通过Condito ...

  5. Spring 梳理-profile与条件化定义bean

    定义profile <beans> //root <beans profile="dev"> <bean id=.../> </beans ...

  6. 【Java Web开发学习】Spring4条件化的bean

    [Java Web开发学习]Spring4条件化的bean 转载:https://www.cnblogs.com/yangchongxing/p/9071960.html Spring4引入了@Con ...

  7. Spring高级装配(二) 条件化的bean

    如果你希望一个bean在特定的条件下才会出现: 应用的类路径下包含特定的库时才创建 只有当某个特定的bean也声明之后才会创建 某个特定的环境变量设定之后才创建某个bean 在Spring 4之前,很 ...

  8. 001profile条件化创建bean

    01.类级别条件创建 @Configuration @Profile("dev") public class Aclass{}---->影响整个类,包括类的注解.开发环境,类 ...

  9. @Condition 条件化注册Bean

    看<Spring源码深度解析>笔记 1.@Condition: 按照一定的条件进行判断,满足条件给容器中注册bean:实例: 根据系统给容器中注册Bean,如果是windows注册(“bi ...

  10. spring对bean的高级装配之基于@Conditional条件化装配

    上篇介绍了如何基于profile来条件化创建bean,spring会根据profile的激活状态来进行创建;这篇介绍如何基于spring4.0引入的@Conditional和Condition接口来更 ...

随机推荐

  1. urllib 模块 https://www.cnblogs.com/guishou/articles/7089496.html

    1.基本方法 urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=Fals ...

  2. Java-性能调优实战(jps、jstack)

    找最耗CPU的线程 1. 找出java进程 [ ~]# jps 9939 Resin 9874 WatchdogManager 9926 Jps 2. 找java进程下所有的线程 [ ~]# top ...

  3. linux 下各个头文件的作用[典]

    linux 下各个头文件的作用   2.6.30.4的头文件的位置和2.6.25.8的不一样,除去内核源码下的include目录外, 在arch/arm/mach-s3c2410/和arch/arm/ ...

  4. 输入n,求1~n累加

    最开始可能会使用for循环来计算,现在直接使用等差数据计算和公式:s=(a0+n)*n/2 long sum(int n) { long ret=0: ret = (1+n)* n /2: retur ...

  5. 构造函数挨个过 —— String()

    本篇整理JavaScript中构造函数String的相关知识,主要分为以下三个部分: 构造函数String()的作用与使用方式: String()的属性和方法: 字符串对象实例属性和方法: 一 构造函 ...

  6. list<>泛型的意义

    泛型就是指定一个自定类或数据类型例如(int)并命名一个XXX集合名,所有这个类型的数据可以加入这个XXXX集合名,组成一个集合. private  list<可放例int数据类型或自定类> ...

  7. from: can't read /var/mail/xxx 解决方法

    在执行一个发包脚本的时候,遇到了如下问题: from: can't read /var/mail/scapy.all 原因:脚本是没有问题的,但它并不是可以被python执行的可执行文件. 解决方法: ...

  8. 两个常见tomcat警告分析

    1. 警告描述: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'source' to 'org.e ...

  9. oracle 顺序号生成函数。仿Sequence

    问题提出自项目中的老代码:一个Bill表,存储所有的表单信息,比如:员工入职单,离职单等等.(别喷,我知道要分多个表.但领导的意愿你是没办法违背的)表单的单据号是以四个字母+年月日+数字顺序号来表示. ...

  10. C5 标准IO库:APUE 笔记

    C5 :标准IO库 在第三章中,所有IO函数都是围绕文件描述符展开,文件描述符用于后续IO操作.由于文件描述符相关的操作是不带缓冲的IO,需要操作者本人指定缓冲区分配.IO长度等,对设备环境要求一定的 ...