【问题标题】:Optional Spring bean references可选的 Spring bean 引用
【发布时间】:2011-04-26 19:48:21
【问题描述】:

在我的应用程序中,我使用 ContextLoaderListener 从许多 jar 中加载上下文文件:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*:META-INF/contextBeans.xml</param-value>
</context-param>

这意味着我可以在不导入的情况下从其他 jar 中引用 bean。

在应用程序中有多个部署选项,并且在某些部署中可以排除 jar。为了支持这一点,我希望一些 bean 引用是可选的。例如:

<bean id="mainAppBean" class="com.someapp.MyApplication">
    <constructor-arg index="0" ref="localBean"/>
     <constructor-arg index="1" ref="optionalBeanReference1"/>
    <constructor-arg index="2" ref="optionalBeanReference2"/>
 </bean>

在上面的示例中,如果未找到引用,我希望 optionalBeanReference1 等于 null(以某种方式将其标记为可选)

这可以在春季完成吗?或者您推荐什么方法来处理动态引用?

【问题讨论】:

    标签: java spring


    【解决方案1】:

    我最好的猜测是使用 autowire-ing 和 required false。不知道如何在 XML 中表达这一点,但使用注解配置如下所示:

    @Autowired(required=false)
    

    【讨论】:

    • 哦,是的,setter 注入可能更适合这种情况。
    • 这听起来不错,但是我现在无法在项目中使用 Spring 注释。
    【解决方案2】:

    使用最新版本的 Spring(使用 spring 4.1 测试)和 Java Configuration 和 Java 8,您可以在参数中使用 Optional,并且仅在可用时自动装配。

    @Autowired
    public MyApplication(Optional<YourOptionalObject> maybeObject) {
        // do something with the optional autowired
    }
    

    【讨论】:

    【解决方案3】:

    您推荐什么方法来处理动态引用?

    我认为@cristian 的@Autowired 答案很好。如果该类型的 bean 可用,它将调用 setter 方法。但是,如果您有多个相同类型的 bean,我相信 Spring 会抛出异常。如果你因为这个或其他原因不能使用@Autowired,我看到了几个解决方案:

    1. 你可以让你的班级ApplicationContextAware 并自己在上下文中查找bean:

      public void setApplicationContext(ApplicationContext applicationContext) {
          if (applicationContext.containsBean("optionalBeanReference1")) {
              setOptionalBeanReference1(
                  (OptionalBeanReference1)applicationContext.bean(
                      "optionalBeanReference1");
          }
          ...
      }
      
    2. 您可以反转依赖关系。每个可选类都可以在 mainAppBean 上设置它们自己。当直接依赖会导致循环或其他问题时,我会在某些情况下使用它。

      <bean id="optionalBeanReference1" class="com.someapp.SomeClass">
          <constructor-arg index="0" ref="mainAppBean"/>
      </bean>
      

      然后在 SomeClass 中:

      public SomeClass(com.someapp.MyApplication mainAppBean) {
          mainAppBean.setOptionalBeanReference1(this);
      }
      
    3. 您可以保留您的直接依赖关系,然后导入一个定义了 bean 的文件,或者导入另一个文件,在其中使用工厂 bean 将 bean 定义为具有空值。看到这个factory code

    祝你好运。

    【讨论】:

    • 我使用了类似于第一个选项的方法,在加载 bean 后,我检查是否还存在其他 bean。这似乎是没有注释的最佳方式
    • 1 似乎是 IoC 的反模式。您正在像服务提供者一样使用 spring。就个人而言,我不喜欢 IoC(有好的方面,但它们不需要失去控制),但要么你使用它,要么你不使用它。乱搞可能是最危险的。
    【解决方案4】:

    鉴于您的 XML 配置中的 bean 引用是通过 表达式语言 (EL) 定义的,您可以执行以下操作:

    <property name="cache" value="#{getObject('optionalCache')}" />
    

    它使用了BeanExpressionContext.getObject() 方法。详情请见here

    【讨论】:

      【解决方案5】:

      对此没有内置机制。但是,您可以编写一个非常简单的 FactoryBean 实现来为您执行此操作,如下所示:

      public class OptionalFactoryBean extends AbstractFactoryBean<Object> implements BeanNameAware {
      
          private String beanName;
      
          @Override
          public void setBeanName(String beanName) {
              this.beanName = BeanFactoryUtils.originalBeanName(beanName);
      
          }
      
          @Override
          protected Object createInstance() throws Exception {
              if (getBeanFactory().containsBean(beanName)) {
                  return getBeanFactory().getBean(beanName);
              } else {
                  return null;
              }
          }
      
          @Override
          public Class<?> getObjectType() {
              return null;
          }
      }
      

      然后你可以像这样使用它:

      <bean id="mainAppBean" class="com.someapp.MyApplication">
          <constructor-arg index="0" ref="localBean"/>    
          <constructor-arg index="1">
             <bean name="optionalBeanReference1" class="com.someapp.OptionalBeanFactory"/>
          </constructor-arg>
          <constructor-arg index="2">
             <bean name="optionalBeanReference2" class="com.someapp.OptionalBeanFactory"/>
          </constructor-arg>
      </bean>
      

      【讨论】:

        猜你喜欢
        • 2012-05-30
        • 1970-01-01
        • 2011-05-15
        • 2016-09-11
        • 2018-07-09
        • 1970-01-01
        • 1970-01-01
        • 2013-01-19
        • 1970-01-01
        相关资源
        最近更新 更多