2010-01-29 11 views
29

Estoy usando Spring para inyectar fábrica de conexiones JMS en mi aplicación Java. Dado que esta fábrica solo se requiere en el entorno de producción, no mientras desarrollo, coloco la definición de bean en un XML separado que incluyo en mi applicationContext.xml principal. En entornos de producción, este archivo adicional contiene la definición regular de bean. En mi entorno de desarrollo local me gustaría que este bean sea nulo. Tratar de simplemente eliminar la definición de bean todos juntos obviamente causó un error cuando Spring encontró una ID de referencia que desconocía.Configurar intencionalmente un bean de resorte para anular

Así que traté de crear un bean de fábrica que simplemente devolvería nulo. Si hago esto, Spring (2.5.x) se queja de que la fábrica devolvió el valor nulo, aunque basado en el documento de Spring API de la interfaz de FactoryBean, esperaba que esto funcionara (ver Spring API doc).

El XML se ve algo como esto:

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

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

Cuál sería la forma "correcta" de hacer esto?

Respuesta

20

factory-bean/factory-method no funciona con null, pero una implementación personalizada FactoryBean funciona bien:

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

Hay una solicitud de función abierta para esto, pero ha estado allí durante 2 años ... votar a favor podría ayudar: http://jira.springframework.org/browse/SPR-5320 – skaffman

+0

Esto no funcionó para mí si usó el bean en un contexto '@ Autowired'. –

+0

Obtengo BeanCreationException si devuelvo nulo. Causado por: org.springframework.beans.factory.BeanCreationException: Error al crear bean con el nombre 'nullObject' definido en el recurso de ruta de clase [XXX.xml]: factory-bean 'NullFactoryBean' devuelto nulo – endless

-1

¿Se puede utilizar el elemento de bean especial <null>? p.ej.

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

de the doc, sección 3.3.2.5

+1

Esto probablemente funcionaría cuando se ajusta el hotel fenomenal del grano de aplicación final. Pero en este punto solo proporciono el id de referencia "jmsConnectionFactory", que entonces debería referirse a un bean real o nulo (si es posible). – Lunikon

27

estoy bastante Asegúrese de que Spring no le permita asociar null con una identificación o nombre de bean. Puede manejar esto estableciendo propiedades en nulo.

Así es como usted hizo esto en la primavera de 2,5

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

En Spring 3.0, también debe ser capaz de utilizar el Spring expression language (SpEL); p.ej.

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

o cualquier expresión que se evalúe como SpEL null.

Y si está utilizando un configurador marcador de posición que podría posiblemente incluso hacer esto:

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

donde some.prop se podría definir en un archivo de propiedades como:

some.prop=null 

o

some.prop=some.bean.id 

Nota, no he usado SpEL (todavía) por lo que podría haber problemas con som e de los anteriores ...

+1

Prefiero esta solución; no necesita la creación de un bean de fábrica personalizado – Richard

4

Como se mencionó anteriormente, la respuesta de axtact no funciona en contextos de Autocableado, donde Spring dependerá de la información correcta del método getObjectType().Por lo que podría terminar con errores como:

 
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 

Así que aquí hay una pequeña variación que consiste en permitir a los usuarios para forzar el objectype en construcción. Usar una propiedad en lugar de un constructor-arg no funcionó porque Spring no inicializa completamente los beans en este contexto.

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; 
    } 
} 
5

Para cualquiera que venga a esta pregunta, tenga en cuenta que el simple ajuste de la anotación @Autowired como opcionales hará el truco (es decir, la primavera dejará la nula referencia si no se encuentra un grano de clasificación).

@Autowired(required = false) 
private SomeClass someBean 

Tenga en cuenta que tendría que hacer esto en todas partes del grano se hace referencia, que puede ser una molestia más grande que la creación de un nulo en fábrica como se mencionó anteriormente.

0

En las pruebas de habas nulos también se puede inyectar como esto:

@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 
Cuestiones relacionadas