java - framework - spring tutorial
Establecer intencionalmente un bean Spring en nulo (6)
Estoy usando Spring para inyectar fábrica de conexiones JMS en mi aplicación Java. Dado que esta fábrica solo es necesaria dentro del entorno de producción, no mientras esté desarrollando, sin embargo, coloco la definición de bean en un XML separado que incluyo en mi aplicación principalContext.xml. 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. Intentar simplemente eliminar la definición del bean all-toghether obviamente causó un error cuando Spring encontró un ID de referencia que no conocía.
Así que traté de crear un bean de fábrica que simplemente devuelva nulo. Si hago esto, Spring (2.5.x) se queja de que la fábrica devolvió el valor nulo, aunque se basó en el documento Spring API de la interfaz de FactoryBean. Esperaba que esto funcionara (consulte el documento Spring API ).
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?
¿Puedes utilizar el elemento de bean especial <null>
? p.ej
<bean class="ExampleBean">
<property name="email"><null/></property>
</bean>
del documento , sección 3.3.2.5.
Como se mencionó anteriormente, la respuesta de axtact no funciona en contextos de Autowiring, donde Spring se basará en la información correcta del método getObjectType (). Entonces podrías 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 implica permitir a los usuarios forzar el tipo de objeto en la 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;
}
}
En las pruebas, los beans nulos también se pueden inyectar así:
@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
Estoy bastante seguro de que Spring no te permitirá asociar null
con una identificación o un alias de bean. Puede manejar esto estableciendo propiedades en nulo.
Así es como lo hiciste en Spring 2.5
<bean class="ExampleBean">
<property name="email"><null/></property>
</bean>
En Spring 3.0, también debería poder usar el lenguaje de expresión Spring (SpEL) ; p.ej
<bean class="ExampleBean">
<property name="email" value="#{ null }"/>
</bean>
o cualquier expresión SpEL que se evalúe como null
.
Y si está utilizando un configurador de marcador de posición, podría incluso hacer esto:
<bean class="ExampleBean">
<property name="email" value="#{ ${some.prop} }`"/>
</bean>
donde some.prop
podría definirse en un archivo de propiedades como:
some.prop=null
o
some.prop=some.bean.id
Tenga en cuenta que no he usado SpEL (todavía), por lo que podría haber problemas con algunos de los anteriores ...
Para cualquier persona que llegue a esta pregunta, tenga en cuenta que simplemente establecer la anotación @Autowired como opcional hará el truco (es decir, Spring dejará la referencia nula si no se encuentra ningún bean calificado).
@Autowired(required = false)
private SomeClass someBean
Tenga en cuenta que tendría que hacer esto en cualquier lugar donde se haga referencia al bean, lo que puede ser una molestia mayor que crear una fábrica nula como se mencionó anteriormente.
factory-bean
/ factory-method
no funciona con null
, pero una implementación personalizada de 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" />