您现在的位置是:首页 >技术杂谈 >Spring高级装配--条件化的bean网站首页技术杂谈

Spring高级装配--条件化的bean

兔子队列 2024-09-21 00:01:02
简介Spring高级装配--条件化的bean

目录

条件化创建bean的例子

使用

解析


  • 条件化创建bean的例子

    • 希望一个或多个bean只有在应用的类路径下包含特定的库时创建
    • 希望某个bean只有当另外某个特定的bean也声明之后才会创建
    • 要求某个特定的环境变量设置之后,才会创建某个bean
  • 在Spring 4之前,很难实现这种级别的条件化配置
  • 但是Spring 4引入了一个新的@Conditional 注解,它可以用到带有@Bean 注解的方法上
  • 如果给定的条件计算结果为true,就会创建这个bean,否则的话,这个bean会被忽略
  • 设想一种应用场景:应用部署在多台服务器上,而想应用的其中某个服务只运行在一台服务器上(比如定时任务或者kafka消息监听处理消息等服务),条件化的bean可以实现此类需求
  • 比如应用上下文在创建某个bean之前,查询数据库,若数据库配置的此环境ip与当前虚机ip一致,则创建,否则则不创建
  • 使用

  • 自定义的条件类IpSameCondition需要实现Condition接口,重写matches()方法即可

  • 可以看出来,这个接口实现起来很简单直接
  • 只需提供matches()方法的实现即可
  • 如果matches()方法返回true,那么就会创建带有@Conditional 注解的bean
  • 如果matches()方法返回false,将不会创建这些bean
  • 解析

  • matches()方法很简单但功能强大
  • 它能通过给定的ConditionContext对象进而得到Environment对象再进行检查
  • 但Condition实现的考量因素可能会比这更多
  • matches()方法会得到ConditionContext和AnnotatedTypeMetadata对象用来做出决策
  • ConditionContext是一个接口,大致如下所示:

  • 通过ConditionContext,我们可以做到如下几点:
    • 借助getRegistry()返回的BeanDefinitionRegistry检查bean定义
    • 借助getBeanFactory()返回的ConfigurableListableBeanFactory检查bean是否存在,甚至探查bean的属性
    • 借助getEnvironment()返回的Environment检查环境变量是否存在以及它的值是什么
    • 读取并探查getResourceLoader()返回的ResourceLoader所加载的资源
    • 借助getClassLoader()返回的ClassLoader加载并检查类是否存在
  • AnnotatedTypeMetadata则能够让我们检查带有@Bean 注解的方法上还有什么其他的注解
  • 像ConditionContext一样,AnnotatedTypeMetadata也是一个接口;它如下所示:

  • 借助isAnnotated()方法,我们能够判断带有@Bean 注解的方法是不是还有其他特定的注解
  • 借助其他的那些方法,我们能够检查@Bean 注解的方法上其他注解的属性
  • 非常有意思的是,从Spring 4开始,@Profile 注解进行了重构,使其基于@Conditional 和Condition实现
  • 作为如何使用@Conditional 和Condition的例子,我们来看一下在Spring 4中,@Profile 是如何实现的

  • @Profile 本身也使用了@Conditional 注解,并且引用ProfileCondition作为Condition实现
  • 如下所示,ProfileCondition实现了Condition接口,并且在做出决策的过程中,考虑到了ConditionContext和AnnotatedTypeMetadata中的多个因素
  • ProfileCondition检查某个bean profile是否可用:

  • 可以看到,ProfileCondition通过AnnotatedTypeMetadata得到了用于@Profile 注解的所有属性
  • 借助该信息,它会明确地检查value属性,该属性包含了bean的profile名称
  • 然后,它根据通过ConditionContext得到的Environment来检查[借助acceptsProfiles()方法]该profile是否处于激活状态
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。