2010-10-18 25 views
16

In meiner Anwendung ich Context bin mit Kontext-Dateien aus vielen Gläsern laden mit:Optional Spring-Bean Referenzen

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

Das bedeutet, ich Bohnen aus anderen Gläsern ohne Import tun verweisen kann.

In der Anwendung gibt es mehrere Bereitstellungsoptionen und in einigen Bereitstellungen können Gläser ausgeschlossen werden. Um dies zu unterstützen, möchte ich, dass einige Bean-Referenzen optional sind. Zum Beispiel:

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

Im Beispiel oben Ich möchte optionalBeanReference1 gleich null haben, wenn der Verweis nicht gefunden wurde (markieren Sie es in irgendeiner Weise optional)

Kann dies im Frühjahr geschehen? oder welche Methode empfehlen Sie für den Umgang mit dynamischen Referenzen?

Antwort

9

welche Methode empfehlen Sie für den Umgang mit dynamischen Referenzen?

Ich denke @ Cristian @Autowired Antwort ist eine gute. Dadurch werden die Setter-Methoden aufgerufen, wenn die Beans dieses Typs verfügbar sind. Wenn Sie mehrere Beans des gleichen Typs haben, wird Spring jedoch eine Ausnahme auslösen. Wenn Sie nicht @Autowired für diesen oder aus einem anderen Grunde verwenden können, sehe ich ein paar Lösungen:

  1. Sie Ihre Klasse ApplicationContextAware machen könnten und Nachschlag die Bohnen im Kontext selbst:

    public void setApplicationContext(ApplicationContext applicationContext) { 
        if (applicationContext.containsBean("optionalBeanReference1")) { 
         setOptionalBeanReference1(
          (OptionalBeanReference1)applicationContext.bean(
           "optionalBeanReference1"); 
        } 
        ... 
    } 
    
  2. Sie können die Abhängigkeit invertieren. Jede der optionalen Klassen könnte selbst auf der MainAppBean setzen. Ich benutze dies in bestimmten Situationen, in denen eine direkte Abhängigkeit Schleifen oder andere Probleme verursachen würde.

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

    Dann im Someclass:

    public SomeClass(com.someapp.MyApplication mainAppBean) { 
        mainAppBean.setOptionalBeanReference1(this); 
    } 
    
  3. Sie mit Ihrem direkten Abhängigkeit bleiben könnte und dann entweder eine Datei importieren mit den Bohnen eine andere Datei definiert oder importieren, in dem Sie die Bohnen definieren Nullwerte haben indem Sie eine Factory-Bean verwenden. Siehe hierzu factory code.

Viel Glück.

+0

Ich habe etwas ähnliches zur ersten Option verwendet, wo ich nach dem Laden der Bean überprüfe, ob auch andere Beans existieren. Das scheint der beste Weg ohne Anmerkungen zu sein. – mbdev

23

Meine beste Schätzung ist die Verwendung autowire -ing mit erforderlichen false. Sie wissen nicht, wie Sie dies in XML zum Ausdruck bringen können, aber unter Verwendung Annotation Konfiguration würde dies wie folgt aussehen:

@Autowired(required=false) 
+1

Oh, ja, und Setter-Injektion ist wahrscheinlich besser für diese Art von Situationen. –

+0

Das klingt gut, aber ich kann Spring-Anmerkungen im Projekt jetzt nicht verwenden. – mbdev

5

Es gibt keinen eingebauten Mechanismus dafür.Sie können jedoch eine ziemlich trivial FactoryBean Implementierung schreiben dies für Sie, so etwas zu tun:

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

können Sie dann wie folgt verwenden:

<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

Da die Bohne Referenzen in Ihrer XML Config über Ausdruckssprache definiert (EL) können Sie wie folgt vorgehen:

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

die nutzt die BeanExpressionContext.getObject() Methode. Weitere Informationen finden Sie unter here.

7

Mit den neuesten Versionen von Spring (getestet mit Spring 4.1) und Java Configuration und Java 8 können Sie optionale Parameter verwenden und werden nur autowired, wenn verfügbar.

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

Hier finden Sie das Spring Improvement Ticket: https://jira.spring.io/browse/SPR-11833 und ein aktuelles Beispiel hier: https://stackoverflow.com/questions/19485878/can -inject-gemacht-optional-in-jsr-330-wie-autowirrequired-false –

+0

das ist die beste Lösung! Es klappt! Vielen Dank! – Torsten