如果你希望一个bean在特定的条件下才会出现:

  • 应用的类路径下包含特定的库时才创建
  • 只有当某个特定的bean也声明之后才会创建
  • 某个特定的环境变量设定之后才创建某个bean

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

示例:设置了magic环境属性才去实例化MagicBean

 @Bean
@Conditional(MagicExistsCondition.class) // 条件化地创建bean
public MagicBean magicBean() {
return new MagicBean();
}

这里的@Conditional中给定了一个Class,它指明了条件,也就是MagicCondition。

Condition接口如下:

 public interface Condition {
boolean matches(ConditionContext ctxt, AnnotatedTypeMetadata metadata);
}

设置给@Conditional的类可以使任意实现了Condition接口的类型。如此一来,只需要提供matches( )方法的实现即可。如果matches( )方法返回为true,那么就会创建带有@Conditional注解的bean。反之则不会创建这些bean。

MagicExistsCondition的实现:

 public class MagicExistsCondition implements Condition {
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment env = context.getEnvironment();
return env.containsProperty("magic"); // 检查是否有magic属性
}
}

上面的例子中只获取了Environment,ConditionContext中的内容还挺丰富的,它是一个接口:

 public interface ConditionContext {
BeanDefinitionRegistry getRegistry();
ConfigurableListableBeanFactory getBeanFactory();
Environment getEnvironment();
ResourceLoader getResourceLoader();
ClassLoader getClassLoader();
}

通过ConditionContext,可以拿到的资源有:

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

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

 public interface AnnotatedTypeMetadata {
boolean isAnnotated(String var1);
Map<String, Object> getAnnotationAttributes(String var1);
Map<String, Object> getAnnotationAttributes(String var1, boolean var2);
MultiValueMap<String, Object> getAllAnnotationAttributes(String var1);
MultiValueMap<String, Object> getAllAnnotationAttributes(String var1, boolean var2);
}

通过isAnnotated方法,我们能够判断带有@Bean注解的方法是不是还有其他特定的注解。借助其他的方法,能够检查@Bean注解的方法上其他注解的属性。

在Spring 4开始,@Profile注解进行了重构,使其基于@Conditional和Condition的实现。

在Spring 4中@Profile的实现如下:

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

ProfileCondition:

 class ProfileCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
if (context.getEnvironment() != null) {
MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
if (attrs != null) {
for (Object value : attrs.get("value")) {
if (context.getEnvironment().acceptsProfiles(((String[]) value))) {
return true;
}
}
return false;
}
}
return true;
}
}

ProfileCondition通过AnnotatedTypeMetadata得到了用于@Profile注解的所有属性。借助该信息,它会明确地检查value属性,该属性包含了bean的profile名称。然后根据ConditionContext得到的Environment来检查(借助acceptsProfiles()方法)该profile是否处于激活状态。

总结

  • @Conditional注解可以实现一个bean的条件化声明
  • Profile在Spring 4中使用@Conditional进行了重构
  • 实现条件化配置中有两个关键的接口:ConditionContext和AnnotatedTypeMetadata,在检测条件的时候起了关键作用
  • 这里没有讲在xml中如何实现条件化配置
  • 这里发现用Java来进行config还是挺爽的

Spring高级装配(二) 条件化的bean的更多相关文章

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

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

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

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

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

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

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

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

  5. Spring高级装配bean

    目录 spring profile 条件化的bean声明 自动装配与歧义性 bean的作用域 Spring表达式语言 一.环境与profile 配置profile  bean 在软件开发的时候,有一个 ...

  6. Spring高级装配

    Spring高级装配 目录 一.Profile(根据开发环境创建对应的bean) 二.条件化的创建bean(根据条件创建bean) 三.处理自动装配歧义性(指定首选bean.限定符限制bean) 四. ...

  7. Spring高级装配(一) profile

    Spring高级装配要学习的内容包括: Spring profile 条件化的bean声明 自动装配与歧义性 bean的作用域 Spring表达式语言 以上属于高级一点的bean装配技术,如果你没有啥 ...

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

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

  9. 002Conditional条件化创建bean

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

随机推荐

  1. Angular 2 + 折腾记 :(7) 初步了解表单:模板驱动及数据驱动及脱坑要点

    前言 表单在整个系统中的作用相当重要,这里主要扯下响应表单的实现方式. 首先须要操作表单的模块引入这两个模块. import { FormsModule, ReactiveFormsModule } ...

  2. Java Nashorn--Part 3

    jjs 的 -Scripting 选项 jjs shell 是一个不错的方法来测试一些基本的 JavaScript,或者于不太熟悉的 JavaScript包进行交互(主要是指 javax.script ...

  3. logstash日志分析的配置和使用(转)

    logstash是一个数据分析软件,主要目的是分析log日志.整一套软件可以当作一个MVC模型,logstash是controller层,Elasticsearch是一个model层,kibana是v ...

  4. Java代码通过API操作HBase的最佳实践

    HBase提供了丰富的API.这使得用Java连接HBase非常方便. 有时候大家会使用HTable table=new HTable(config,tablename);的方式来实例化一个HTabl ...

  5. 基于数据库构建分布式的ID生成方案

    在分布式系统中,生成全局唯一ID,有很多种方案,但是在这多种方案中,每种方案都有有缺点,下面我们之针对通过常用数据库来生成分布式ID的方案,其它方法会在其它文中讨论: 1,RDBMS生成ID: 这里我 ...

  6. ELK 的插件安装(head)

    这里我装了一个head插件和kopf的插件 ./plugin install mobz/elasticsearch-head ./plugin install lmenezes/elasticsear ...

  7. 在 Unity 中基于 Oculus DK1 的开发

    开发环境: Windows 10 专业版 64位(GeForce GTX 970M,驱动版本:378.72) 大朋助手 1.3.2.10,大朋E2(http://www.deepoon.com/dap ...

  8. [WebGL入门]十八,利用索引缓存来画图

    注:文章译自http://wgld.org/.原作者杉本雅広(doxas),文章中假设有我的额外说明.我会加上[lufy:].另外,鄙人webgl研究还不够深入,一些专业词语,假设翻译有误,欢迎大家指 ...

  9. 使用Vuex打开log功能

    vuex是一个比较好用的数据流管理库,可以用统一的流程来处理状态数据,但是,也正是因为这些流程,我们需要打一些log来观察流程是否会出现问题,具体方法如下: import Vue from 'vue' ...

  10. java集群优化——ORM框架查询优化原理

    众所周知,当下的流行的企业级架构中,ORM一直是最基础的部分,在架构设计的底层.对逻辑层提供面向对象的操作支持,而事实总是和我们预想的有所偏差,ORM在提供了较好的操作体验时,也流失了一部分原生SQL ...