Java 可选的 Spring bean 引用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3957430/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 07:34:17  来源:igfitidea点击:

Optional Spring bean references

javaspring

提问by mbdev

In my application I am using ContextLoaderListener to load context files from many jars using:

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

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

This means I can reference beans from other jars without doing import.

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

In the application there are multiple deployment options and in some deployments jars can be excluded. To support that I would like some bean references to be optional. For example:

在应用程序中有多个部署选项,并且在某些部署中可以排除 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>

In the example above I would like to have optionalBeanReference1 equal null if the reference was not found (mark it optional in some way)

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

Can this be done in Spring? or what method do you recommend for handling dynamic references?

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

采纳答案by Gray

what method do you recommend for handling dynamic references?

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

I think @cristian's @Autowired answer is a good one. That will call the setter methods if the beans of that type are available. However, if you have multiple beans of the same type, I believe Spring throws an exception. If you cannot use @Autowired for this or some other reason, I see a couple of solutions:

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

  1. You could make your class ApplicationContextAwareand lookup the beans in the context yourself:

    public void setApplicationContext(ApplicationContext applicationContext) {
        if (applicationContext.containsBean("optionalBeanReference1")) {
            setOptionalBeanReference1(
                (OptionalBeanReference1)applicationContext.bean(
                    "optionalBeanReference1");
        }
        ...
    }
    
  2. You could invert the dependency. Each of the optional classes could set themselveson the mainAppBean. I use this in certain situations when a direct dependency would cause loops or other problems.

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

    Then in the SomeClass:

    public SomeClass(com.someapp.MyApplication mainAppBean) {
        mainAppBean.setOptionalBeanReference1(this);
    }
    
  3. You could stay with your direct dependency and then either import a file with the beans defined or import another file where you define the beans as having null values by using a factory bean. See this factory code.

  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 定义为具有空值。请参阅此工厂代码

Good luck.

祝你好运。

回答by Cristian Vrabie

My best guess is to use autowire-ing with required false. Don't know how you can express this in XML but using annotation configuration this would look like:

我最好的猜测是使用autowire-ing 和 required false。不知道如何在 XML 中表达这一点,但使用注释配置,这看起来像:

@Autowired(required=false)

回答by skaffman

There's no built-in mechanism for this. However, you could write a pretty trivial FactoryBeanimplementation to do this for you, something like this:

对此没有内置机制。但是,您可以编写一个非常简单的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;
    }
}

You can then use it like this:

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

<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>

回答by Brian Agnew

Given that the bean references in your XML config are defined via expression language(EL) you can do the following:

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

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

which makes use of the BeanExpressionContext.getObject()method. See herefor more details.

它利用了该BeanExpressionContext.getObject()方法。请参阅此处了解更多详情。

回答by aseychell

With recent versions of Spring (tested with spring 4.1) and Java Configuration and Java 8, you can use Optional in parameters, and are only autowired if available.

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

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