2009-11-28 4 views
6

Wir haben einige Domain-Objekte, die zur Laufzeit erstellt werden - nicht von Spring. Diese Domänenobjekte benötigen Zugriff auf einige Servicetyp-Beans, die von Spring verwaltet werden. Wie können die Domänenobjekte, die zur Laufzeit erstellt werden, dynamisch auf Spring Beans zugreifen (nicht über DI)?Zugreifen auf Spring-Bean * not * durch Dependency-Injektion

Antwort

7

Sie müssen ihnen einen Verweis auf den ApplicationContext oder BeanFactory geben, damit sie die Spring-verwalteten Beans erhalten können.

+1

Was ist die beste Praxis ist diese App in einem Web zu tun? Ist es üblich, dass dynamisch erstellte Domänenobjekte auf diese Weise auf Spring Beans zugreifen müssen? –

+1

Ich würde empfehlen, WebApplicationContextUtils zu sehen: http://static.springsource.org/spring/docs/3.0.0.RC1/javadoc-api/. Ich denke, es ist üblicher, Spring die Bohnen zu verwalten. Nur lokale Beans in einem Methodenaufrufkontext würden mit "new" erstellt werden. – duffymo

0

Sie könnten den Ansatz verwenden, den @duffymo vorgeschlagen hat, aber für den Fall, dass Sie Spring nicht als Webanwendung ausführen, sollten Sie sich diese SO entry ansehen. Beachten Sie, dass die Dienstprogrammklasse in der beliebtesten Antwort threadsicher ist. Neben dem OP und der Antwort sollten Sie alles bekommen, was Sie brauchen, und dann können Sie diese Dienstprogrammklasse verwenden, um einen Verweis auf die von Spring verwalteten Beans zu erhalten.

8

@ Duffymos Antwort ist die häufigste Lösung für dieses Problem und die, der Sie wahrscheinlich folgen sollten.

Wenn Sie jedoch keck fühlen, und wenn Sie Ihre Situation unterstützt, dann könnte man mit Spring AspectJ Unterstützung autowire your non-spring-managed domain objects mit Feder Bohnen betrachten:

[...] enthält eine Anmerkung-driven Aspekt, der diese Fähigkeit nutzt, um die Abhängigkeitsinjektion eines beliebigen Objekts zuzulassen. Die Unterstützung soll für Objekte verwendet werden, die außerhalb von die Steuerung eines beliebigen Containers erstellt werden. Domäne Objekte fallen oft in diese Kategorie , weil sie oft programmgesteuert mit dem neuen Operator oder von einem ORM-Tool als Ergebnis einer Datenbankabfrage erstellt werden.

Es ist fast Voodoo, dieses Zeug, und es funktioniert nur auf bestimmte Anwendungen, aber es könnte das Werkzeug für Sie sein.

3

Spring hat einen Mechanismus namens SingletonBeanFactoryLocator, den Sie an Orten wie EJB 2.0-Anwendungen verwenden können, um den Bean-Factory-/Anwendungskontext an Stellen zu erhalten, an denen Sie die Abhängigkeitsinjektion nicht verwenden können. Es gibt einen Haken in der vorhandenen Spring ContextLoader, die Sie bereits verwenden, um diese Funktionalität zu nutzen, obwohl es etwas schwierig einzurichten ist.

Sie müssen Ihre Anwendungskontexte in eine Eltern/Kind-Beziehung trennen. Das übergeordnete Element enthält die Service-Layer-Objekte, während das untergeordnete Element aus dem weblayerspezifischen Material besteht.

Dann werden Sie ein paar Kontextparameter zu Ihrem web.xml hinzufügen müssen (wie Sie für die Konfigurations Lage tun) es zu sagen, die Eltern zu initialisieren:

<context-param> 
    <param-name>locatorFactorySelector</param-name> 
    <param-value>classpath:beanRefFactory.xml</param-value> 
</context-param> 

<context-param> 
    <param-name>parentContextKey</param-name> 
    <param-value>beanRefFactory</param-value> 
</context-param> 

Die locatorFactorySelector ist eine Referenz zu einer XML-Datei, ABER (das ist, wo ich immer verwirrt) wird dies nicht auf das XML, das Ihre Dienste definiert. Es ist ein Bean-Definition-XML, das eine Anwendungskontext-Bean erstellt. Dass Sie dann mit dem Attribut parentContextKey auf diese Bean verweisen.

So zum Beispiel beanRefFactory.xml würde dann enthalten:

<beans> 
    <bean id="beanRefFactory" 
     class="org.springframework.context.support.ClassPathXmlApplicationContext"> 
     <constructor-arg> 
      <list> 
       <value>service-context.xml</value> 
      </list> 
     </constructor-arg> 
    </bean> 
</beans> 

in Ihren nicht-died Domain-Objekten, können Sie dann mit diesem Code auf den Anwendungskontext erhalten:

BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance(locatorFactorySelector); 
    BeanFactoryReference contextRef= locator.useBeanFactory(parentContextKey); 
    ApplicatonContext context = (ApplicationContext) contextRef.getFactory(); 

Sie können weitere Informationen über ContextSingletonBeanFactoryLocator in this blog post finden. Es gibt auch eine gute Beschreibung der Verwendung dieses Ansatzes im Kapitel über EJBs in Java Development with the Spring Framework.

0

Eine Lösung ist eine globale static Methode zu verwenden, die den Spring-Anwendungs ​​Wettbewerb zurückzugibt (siehe BeanLocator.)

Andere Optionen könnte Ihre Business-Objekte implementieren die ApplicationContextAware Schnittstelle zu haben. Bei der Instanziierung müsste Ihr "Integrations" -Code das Spring ApplicationContext in das dynamisch erstellte Bean einspeisen (z. B. indem überprüft wird, ob die Klasse ApplicationContextAware implementiert). Dies würde Ihren Geschäftscode natürlich mit Spring verknüpfen, aber die erste Option wäre dieselbe .

Eine Variante wäre, die ApplicationContext nicht direkt zu injizieren, sondern die Spring @Autowired Annotation wiederzuverwenden. Der "Integrations" -Code würde dann nur die annotierten Felder injizieren.

3

eine Fabrik erstellen und es mit Feder registrieren, die Fabrik verwenden, um Domain-Objekt anstatt mit ‚neuen‘

in diesem Fall zu erstellen, haben Sie alle Goodies Verfügung, um Ihre DomainObjFactory

1

Leicht question bezogen

Sie könnten eine ähnliche Strategie wie Hibernate anwenden, indem Sie Einrichtungen für Interzeptoren in Ihrer Domäneninstanz-Factory erstellen. Sie können die erforderlichen Dienste in im Frühjahr verwaltete Abfangvorrichtungen injizieren, die in Ihre Domänenfabriken injiziert werden.

Dies würde Ihre Anwendung von Spring-spezifischen Schnittstellen lösen. Das folgende Beispiel könnte mit Generics vereinfacht werden, aber Sie sollten die Idee bekommen.

public interface Interceptor { 
    public void onCreate(Object entity); 
} 

public class DomainFactory { 
    public void setInterceptors(List<Interceptor> interceptors) { ... } 
    public Object createInstance() { 
    // iterate interceptors, call onCreate 
    } 
} 

public interface MyServiceAware { 
    public void setMyService(MyService service); 
} 

public class MyServiceInjector implements Interceptor { 
    private MyService myService; 
    public void onCreate(Object entity) { 
    if (entity instanceof MyServiceAware) 
     ((MyServiceAware) entity).setMyService(myService); 
    } 
} 

Dann würden Sie es so konfigurieren, so etwas wie

<bean id="myServiceInjector" class="MyServiceInjector"> 
    <property name="myService" ref="someServiceBean" /> 
</bean> 

<bean class="DomainFactory"> 
    <property name="interceptors"> 
    <list> 
     <ref bean="myServiceInjector"/> 
    </list> 
    </property> 
</bean> 
0

Sie könnten das abhängige Objekt einen Singleton mit einer statischen Methode getInstance() machen, die durch die nicht-Spring-verwalteten Domain-Objekte verwendet werden könnte. Sie würden dann wie Spring über org.springframework.beans.factory.config.MethodInvokingFactoryBean zur Verfügung stellen:

<bean id="myObject" 
    class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> 
    <property name="staticMethod"> 
     <value>com.example.MyObject.getInstance</value> 
    </property> 
</bean> 
Verwandte Themen