Java 故意将 Spring bean 设置为 null

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2163182/
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-13 04:16:22  来源:igfitidea点击:

Intentionally setting a Spring bean to null

javaspring

提问by Lunikon

I'm using Spring to inject JMS connection factory into my Java application. Since this factory is only required within the production environment, not while I'm developing though, I put the bean definition into a separate XML which I include into my main applicationContext.xml. In production environments this extra file contains the regular bean definition. In my local dev environment I'd like this bean to be null. Trying to simply remove the bean definition all-toghether obviously caused an error when Spring came across a reference ID it didn't know.

我正在使用 Spring 将 JMS 连接工厂注入到我的 Java 应用程序中。由于此工厂仅在生产环境中需要,但在我开发时不需要,因此我将 bean 定义放入单独的 XML 中,并将其包含到我的主 applicationContext.xml 中。在生产环境中,此额外文件包含常规 bean 定义。在我的本地开发环境中,我希望这个 bean 为空。当 Spring 遇到一个它不知道的引用 ID 时,试图简单地一起删除 bean 定义显然会导致错误。

So I tried creating a factory bean that would simply return null. If I do this, Spring (2.5.x) complains that the factory returned null although based on the Spring API doc of the FactoryBean interface I expected this to work (see Spring API doc).

所以我尝试创建一个只会返回 null 的工厂 bean。如果我这样做,Spring (2.5.x) 会抱怨工厂返回 null,尽管基于 FactoryBean 接口的 Spring API 文档,我预计这会起作用(请参阅Spring API 文档)。

The XML looks something like this:

XML 看起来像这样:

<bean id="jmsConnectionFactoryFactory" class="de.airlinesim.jms.NullJmsConnectionFactoryFactory" />

<bean id="jmsConnectionFactory" factory-bean="jmsConnectionFactoryFactory" factory-method="getObject"/>

What would be the "correct" way of doing this?

这样做的“正确”方法是什么?

采纳答案by axtavt

factory-bean/factory-methoddoesn't work with null, but a custom FactoryBeanimplementation works fine:

factory-bean/factory-method不适用于null,但自定义FactoryBean实现可以正常工作:

public class NullFactoryBean implements FactoryBean<Void> {

    public Void getObject() throws Exception {
        return null;
    }

    public Class<? extends Void> getObjectType() {
        return null;
    }

    public boolean isSingleton() {
        return true;
    }
}
<bean id="jmsConnectionFactory" class = "com.sample.NullFactoryBean" />

回答by Brian Agnew

Can you make use of the special <null>bean element ? e.g.

你能利用特殊的<null>bean元素吗?例如

<bean class="ExampleBean">
<property name="email"><null/></property>
</bean>

from the doc, section 3.3.2.5

来自文档,第 3.3.2.5 节

回答by Stephen C

I'm pretty sure that Spring won't allow you to associate nullwith a bean id or alias. You can handle this by setting properties to null.

我很确定 Spring 不允许您null与 bean id 或别名相关联。您可以通过将属性设置为 null 来处理此问题。

Here's how you did this in Spring 2.5

这是您在 Spring 2.5 中的做法

<bean class="ExampleBean">
    <property name="email"><null/></property>
</bean>

In Spring 3.0, you should also be able to use the Spring expression language (SpEL); e.g.

在 Spring 3.0 中,您还应该能够使用Spring 表达式语言 (SpEL);例如

<bean class="ExampleBean">
    <property name="email" value="#{ null }"/>
</bean>

or any SpEL expression that evaluates to null.

或任何计算结果为null.

And if you are using a placeholder configurator you could possibly even do this:

如果您使用占位符配置器,您甚至可以这样做:

<bean class="ExampleBean">
    <property name="email" value="#{ ${some.prop} }`"/>
</bean>

where some.propcould be defined in a property file as:

wheresome.prop可以在属性文件中定义为:

some.prop=null

or

或者

some.prop=some.bean.id

回答by coffeebreaks

Some noted above, axtact's answer doesn't work in Autowiring contextes, where Spring will rely on correct information from the getObjectType() method. So you might end up with errors like:

上面提到的一些,axtact 的答案在自动装配上下文中不起作用,其中 Spring 将依赖来自 getObjectType() 方法的正确信息。所以你最终可能会遇到如下错误:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [xxxxxxxxxxxxx] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=yyyyyyyyyyyyyyyy)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:920)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:789)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:703)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotatio

So here's a small variation which involves allowing users to force the objectype at construction. Using a property instead of a constructor-arg didn't work because Spring doesn't fully initialize the beans in this context.

所以这里有一个小的变化,它涉及允许用户在构造时强制对象类型。使用属性而不是构造函数参数不起作用,因为 Spring 没有在此上下文中完全初始化 bean。

public class NullFactoryBean implements FactoryBean {
    private final Class<?> objectType;

    public NullFactoryBean(Class<?> objectType) {
        this.objectType = objectType;
    }

    @Override
    public Object getObject() throws Exception {
        return null;
    }

    @Override
    public Class<?> getObjectType() {
        return objectType;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }
}

回答by Gerardo Lastra

For anyone coming to this question, keep in mind that simply setting the @Autowired annotation as optional will do the trick (i.e. Spring will leave the reference null if no qualifying bean is found).

对于遇到此问题的任何人,请记住,只需将 @Autowired 注释设置为可选即可解决问题(即,如果未找到符合条件的 bean,Spring 将保留引用为空)。

@Autowired(required = false)
private SomeClass someBean

Note that you would have to do this everywhere the bean is referenced, which may be a bigger hassle than creating a null-factory as mentioned above.

请注意,您必须在引用 bean 的任何地方执行此操作,这可能比如上所述创建空工厂更麻烦。

回答by Vadzim

In tests null beans can also be injected like this:

在测试中,也可以像这样注入空 bean:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = NullTest.class)
@Configuration
public class NullTest {

    @Bean(name = "em")
    public IEntityManager em() { return null; }
    @Bean
    public PlatformTransactionManager tm() { return null; }

    @Resource
    private SomeBean someBean; // this would get em and tm fields autowired to nulls

回答by Rutabaga Man

For anyone else who comes across this: another approach if you're using Java 8 is to use the Supplierfunctional interface to wrap a potentially null bean:

对于遇到此问题的任何其他人:如果您使用 Java 8,另一种方法是使用Supplier函数式接口来包装潜在的空 bean:

@Bean
@Scope("singleton")
public Supplier<SomeBean> getSomeBean() {
  SomeBean myBean = null;  // or can set to a SomeBean instance
  return () -> myBean;
}

With @Autowiredconstructor injection using this looks like:

使用@Autowired构造函数注入看起来像:

private SomeBean someBean;

@Autowired
SomeService(Supplier<SomeBean> someBeanSupplier) {
    this.someBean = someBeanSupplier.get();
}

Then the someBeanfield in SomeServicecan either be null or non-null.

然后someBean字段 inSomeService可以为空或非空。