2010-10-18 22 views
16

Nella mia applicazione sto usando ContextLoaderListener per caricare i file di contesto da molti vasi usando:riferimenti bean Spring opzionali

<context-param> 
    <param-name>contextConfigLocation</param-name> 
    <param-value>classpath*:META-INF/contextBeans.xml</param-value> 
</context-param> 

Questo significa che posso fare riferimento fagioli di altri vasi senza fare importazione.

Nell'applicazione sono disponibili più opzioni di implementazione e in alcuni tipi di contenitori possono essere esclusi. Per supportare questo vorrei che alcuni riferimenti a bean fossero facoltativi. Per esempio:

<bean id="mainAppBean" class="com.someapp.MyApplication"> 
    <constructor-arg index="0" ref="localBean"/> 
    <constructor-arg index="1" ref="optionalBeanReference1"/> 
    <constructor-arg index="2" ref="optionalBeanReference2"/> 
</bean> 

Nell'esempio di cui sopra mi piacerebbe avere optionalBeanReference1 uguale null se non è stato trovato il riferimento (marcarlo facoltativa in qualche modo)

questo può essere fatto in primavera? o quale metodo raccomandi per la gestione dei riferimenti dinamici?

risposta

9

quale metodo mi consigliate per la gestione di riferimenti dinamici?

Penso che la risposta @Autowired di @ cristian sia buona. Questo chiamerà i metodi setter se i fagioli di quel tipo sono disponibili. Tuttavia, se hai più bean dello stesso tipo, credo che Spring lanci un'eccezione. Se non è possibile utilizzare @Autowired per questo o per qualche altra ragione, vedo un paio di soluzioni:

  1. Si potrebbe fare la vostra classe ApplicationContextAware e occhiata i fagioli in un contesto da soli:

    public void setApplicationContext(ApplicationContext applicationContext) { 
        if (applicationContext.containsBean("optionalBeanReference1")) { 
         setOptionalBeanReference1(
          (OptionalBeanReference1)applicationContext.bean(
           "optionalBeanReference1"); 
        } 
        ... 
    } 
    
  2. È possibile invertire la dipendenza. Ciascuna delle classi facoltative potrebbe impostare come sul mainAppBean. Lo uso in determinate situazioni quando una dipendenza diretta causerebbe loop o altri problemi.

    <bean id="optionalBeanReference1" class="com.someapp.SomeClass"> 
        <constructor-arg index="0" ref="mainAppBean"/> 
    </bean> 
    

    Poi nel SomeClass:

    public SomeClass(com.someapp.MyApplication mainAppBean) { 
        mainAppBean.setOptionalBeanReference1(this); 
    } 
    
  3. Si può stare con la vostra dipendenza diretta e poi o importare un file con i fagioli definiti o importare un altro file in cui si definiscono i fagioli come avere valori nulli utilizzando un bean di fabbrica. Vedi questo factory code.

Buona fortuna.

+0

Ho usato qualcosa di simile alla prima opzione, dove dopo che il bean è stato caricato, controllo se esistono anche altri bean. Questo sembra il modo migliore senza annotazioni – mbdev

23

La mia ipotesi migliore è utilizzare autowire -ing con falso richiesto. Non so come si può esprimere questo in XML di configurazione, ma l'annotazione di utilizzare questo sarebbe simile:

@Autowired(required=false) 
+1

Oh, sì, e l'iniezione setter è probabilmente migliore per questo tipo di situazioni. –

+0

Questo suona bene, ma per il momento non riesco a utilizzare le annotazioni Spring nel progetto. – mbdev

5

Non esiste un meccanismo integrato per questo.Tuttavia, si potrebbe scrivere un piuttosto banale FactoryBean implementazione di fare questo per voi, qualcosa di simile:

public class OptionalFactoryBean extends AbstractFactoryBean<Object> implements BeanNameAware { 

    private String beanName; 

    @Override 
    public void setBeanName(String beanName) { 
     this.beanName = BeanFactoryUtils.originalBeanName(beanName); 

    } 

    @Override 
    protected Object createInstance() throws Exception { 
     if (getBeanFactory().containsBean(beanName)) { 
      return getBeanFactory().getBean(beanName); 
     } else { 
      return null; 
     } 
    } 

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

è possibile utilizzare in questo modo:

<bean id="mainAppBean" class="com.someapp.MyApplication"> 
    <constructor-arg index="0" ref="localBean"/>  
    <constructor-arg index="1"> 
     <bean name="optionalBeanReference1" class="com.someapp.OptionalBeanFactory"/> 
    </constructor-arg> 
    <constructor-arg index="2"> 
     <bean name="optionalBeanReference2" class="com.someapp.OptionalBeanFactory"/> 
    </constructor-arg> 
</bean> 
4

Dato che i riferimenti di fagioli nel vostro XML config sono definiti tramite linguaggio delle espressioni (EL) è possibile effettuare le seguenti operazioni:

<property name="cache" value="#{getObject('optionalCache')}" /> 

che fa uso di il metodo BeanExpressionContext.getObject(). Vedi here per maggiori dettagli.

7

Con le versioni recenti di Spring (testate con spring 4.1) e Java Configuration e Java 8, è possibile utilizzare i parametri Optional e, solo se disponibili, sono autowired.

@Autowired 
public MyApplication(Optional<YourOptionalObject> maybeObject) { 
    // do something with the optional autowired 
} 
+1

Vedi il biglietto di miglioramento della primavera qui: https://jira.spring.io/browse/SPR-11833 e un esempio reale qui: https://stackoverflow.com/questions/19485878/can -inject-be-made-optional-in-jsr-330-like-autowirerequired-false –

+0

questa è la soluzione migliore! Funziona! Grazie! – Torsten