故意将Spring bean设置为null

时间:2010-01-29 16:04:27

标签: java spring

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

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

XML看起来像这样:

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

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

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

7 个答案:

答案 0 :(得分:29)

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

以下是你在Spring 2.5中的表现

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

在Spring 3.0中,您还应该能够使用Spring expression language (SpEL); e.g。

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

或任何评估为null的SpEL表达式。

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

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

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

some.prop=null

some.prop=some.bean.id

答案 1 :(得分:21)

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

答案 2 :(得分:9)

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

@Autowired(required = false)
private SomeClass someBean

请注意,在引用bean的每个地方都必须这样做,这可能比创建如上所述的null-factory更麻烦。

答案 3 :(得分:4)

上面提到的一些,axtact的答案在Autowiring上下文中不起作用,其中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

所以这里有一个小变化,它允许用户在构造时强制使用对象类型。使用属性而不是构造函数arg不起作用,因为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;
    }
}

答案 4 :(得分:0)

在测试中,null 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

答案 5 :(得分:0)

对于遇到此问题的其他人:如果您使用的是Java 8,另一种方法是使用Supplier功能接口包装可能为空的bean:

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

使用@Autowired构造函数注入,如下所示:

private SomeBean someBean;

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

然后,someBean中的SomeService字段可以为null或非null。

答案 6 :(得分:-1)

你能使用特殊的<null> bean元素吗? e.g。

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

来自the doc,第3.3.2.5节