2010-01-29 14 views
29

Sto utilizzando Spring per iniettare factory di connessione JMS nella mia applicazione Java. Dato che questo factory è richiesto solo all'interno dell'ambiente di produzione, non mentre sto sviluppando, ho messo la definizione del bean in un XML separato che includo nel mio applicationContext.xml principale. Negli ambienti di produzione questo file extra contiene la normale definizione del bean. Nel mio ambiente dev locale mi piacerebbe che questo bean fosse nullo. Cercando di rimuovere semplicemente la definizione del bean, tutto ovviamente ha causato un errore quando Spring ha trovato un ID di riferimento che non conosceva.Impostare intenzionalmente un bean Spring su null

Così ho provato a creare un bean factory che restituirebbe semplicemente null. Se faccio questo, Spring (2.5.x) si lamenta che il factory ha restituito null sebbene, sulla base del documento Spring API dell'interfaccia FactoryBean, mi aspettavo che funzionasse (vedi Spring API doc).

L'XML sembra qualcosa di simile:

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

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

Quale sarebbe il modo "corretto" di fare questo?

risposta

20

factory-bean/factory-method non funziona con null, ma un'implementazione personalizzata FactoryBean funziona bene:

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

C'è una richiesta di funzionalità aperta per questo, ma ci siamo seduti da 2 anni ... votare per questo potrebbe aiutare: http://jira.springframework.org/browse/SPR-5320 – skaffman

+0

Questo non ha funzionato per me se ho usato il bean in un contesto '@ Autowired'. –

+0

Ottengo BeanCreationException se restituisco null. Causato da: org.springframework.beans.factory.BeanCreationException: Errore nella creazione di bean con nome 'nullObject' definito nella risorsa del percorso di classe [XXX.xml]: factory-bean 'NullFactoryBean' restituito null – endless

-1

È possibile utilizzare lo speciale elemento fagiolo <null>? per esempio.

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

da the doc, sezione 3.3.2.5

+1

Questo probabilmente funziona quando si imposta il propery del fagiolo applicazione finale. Ma a questo punto mi limito a fornire l'id di riferimento "jmsConnectionFactory" che dovrebbe quindi fare riferimento a un bean effettivo o null (se ciò è possibile a tutti). – Lunikon

27

Sono abbastanza certo che Spring non ti permetterà di associare null con un id o un alias di bean. Puoi gestirlo impostando le proprietà su null.

Ecco come avete fatto queste cose a Spring 2,5

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

In Primavera 3.0, si dovrebbe anche essere in grado di utilizzare il Spring expression language (SpEL); per esempio.

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

o qualsiasi espressione SPEL che restituisce null.

E se si sta utilizzando un configuratore segnaposto si potrebbe anche fare questo:

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

dove some.prop può essere definito in un file di proprietà come:

some.prop=null 

o

some.prop=some.bean.id 

Nota, non ho ancora usato SpEL (quindi), quindi potrebbero esserci problemi con e di quanto sopra ...

+1

Preferisco di gran lunga questa soluzione; non richiede la creazione di un bean di fabbrica personalizzato – Richard

4

Alcuni noti sopra, la risposta di axtact non funziona nei contesti di Autowiring, dove Spring si baserà su informazioni corrette dal metodo getObjectType().Così si potrebbe finire con errori come:

 
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 

Quindi, ecco una piccola variazione che coinvolge consentendo agli utenti di forzare l'objectype a costruzione. L'utilizzo di una proprietà anziché di un argomento di costruzione non ha funzionato perché Spring non inizializza completamente i bean in questo contesto.

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

per chi viene a questa domanda, tenere a mente che semplicemente impostando l'annotazione @Autowired come optional farà il trucco (vale a dire primavera lascerà il nulla di riferimento se non viene trovata fagioli di qualificazione).

@Autowired(required = false) 
private SomeClass someBean 

noti che si dovrebbe fare questo in tutto il mondo il fagiolo viene fatto riferimento, che può essere una seccatura più grande di creare un null-fabbrica di cui sopra.

0

Nei test fagioli nulli può anche essere iniettato simili:

@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 
Problemi correlati