2010-03-13 18 views
9

Sto tentando di implementare un fornitore di servizi delegato sovrascrivendo la definizione del bean per il servizio originale con il mio servizio delegato. Tuttavia, come implicherebbe il nome, il servizio delegato necessita di un riferimento al servizio originale per delegare le chiamate a.Come sovrascrivere una definizione di bean Spring e fare ancora riferimento al bean sottoposto a override?

Non riesco a capire come sovrascrivere la definizione del bean mentre si utilizza il bean def originale senza eseguire un riferimento circolare.

Ad esempio:

<!-- Original service def in spring-context.xml --> 
<bean id="service" class="com.mycompany.Service"/> 

<!-- Overridden definition in spring-plugin-context.xml --> 
<bean id="service" class="com.mycompany.DelegatedService"/> 
    <constructor-arg ref="service"/> 
</bean> 

è possibile?

risposta

10

Il corto rispondere alla tua domanda è che non puoi avere due definizioni di bean con lo stesso nome. Se ci provi, uno nasconderà l'altro e solo una definizione sarà utilizzabile.

L'esempio della domanda sembra suggerire che si sta tentando di avvolgere il bean originale service in un oggetto proxy, con il wrapper che esegue un po 'di lavoro prima e dopo le chiamate al servizio. Un modo per ottenere ciò, senza definire due bean service e senza modificare il bean originale service, è utilizzare una molla AutoProxyCreator, probabilmente un BeanNameAutoProxyCreator.

Ciò consente di elencare un bean (o bean) che deve essere automaticamente proxy. Si specificano gli intercettori che si desidera applicare alle chiamate sul bean di destinazione. Dovresti implementare questi intercettori per fare il lavoro che devi fare.

Spring creerebbe automaticamente un proxy delegante per te, che avrebbe l'ID bean service come prima, ma con le tue funzionalità aggiuntive.

+0

Questa risposta è stata la più utile anche se il mio problema si è rivelato irrisolvibile. Al fine di delegare la classe, deve essere tessuta da un aspetto. Poiché la classe che stavo tentando di eseguire il proxy era già stata compilata ed eseguita in un classloader diverso, non ero in grado di eseguire il proxy. – Kevin

+0

@Kevin: un 'AutoProxyCreator' non esegue il proxy delle classi, genera proxy di bean. Non dovrebbe importare quale classloader carichi la classe target, è l'oggetto target che è proxy e Spring istanzia quell'oggetto target. – skaffman

+0

per rispondere alla domanda originale, uno schema è semplicemente dichiarare un bean sottostante "nudo". in una configurazione l'alias al nome del bean di destinazione, nell'altra configurazione definire il proprio wrapper che viene iniettato con il bean sottostante. questo richiede in anticipo una pianificazione. – aaron

2

È possibile creare proxies and interceptors. Così ora il bean chiamato service diventerà un proxy all'originale service che deve essere rinominato in qualcos'altro. Quindi le modifiche saranno limitate solo al codice XML Spring e non saranno propagate al codice java.

<bean id="personTarget" class="com.mycompany.PersonImpl"> 
    <property name="name"><value>Tony</value></property> 
    <property name="age"><value>51</value></property> 
</bean> 

<bean id="myAdvisor" class="com.mycompany.MyAdvisor"> 
    <property name="someProperty"><value>Custom string property value</value></property> 
</bean> 

<bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor"> 
</bean> 

<bean id="person" 
    class="org.springframework.aop.framework.ProxyFactoryBean"> 
    <property name="proxyInterfaces"><value>com.mycompany.Person</value></property> 

    <property name="target"><ref local="personTarget"/></property> 
    <property name="interceptorNames"> 
     <list> 
      <value>myAdvisor</value> 
      <value>debugInterceptor</value> 
     </list> 
    </property> 
</bean> 
+0

Non riesco a rinominare il bean "servizio" originale in qualcos'altro perché è definito in un contesto di primavera che è fuori dal mio controllo – Kevin

+0

AFAIK, che è impossibile in primavera. Inoltre, anche se fosse possibile sarebbe una cattiva pratica, se qualcuno scrivesse il bean con una particolare funzionalità in mente e lo chiudesse alle modifiche, si potrebbe finire per rompere la funzionalità originale. Una (cattiva) soluzione sarà quella di definire la propria classe con la stessa firma e utilizzare un caricatore di classi personalizzato per caricare la classe originale e delegare ad essa. Sarebbe meglio se potessi pubblicare il tuo requisito di fine. – saugata

1

Sembra che tu stia cercando di reinventare Spring-AOP. Si prega di considerare l'utilizzo di spring-AOP per questo.

È possibile modificare in modo programmatico il nome del servizio esistente e creare un nuovo bean con il vecchio nome. Il codice di autoproxying nel framework di primavera fa questo e potresti dare un'occhiata a questo. Una ricerca rapida del codice per Auto Proxy * nel framework primavera dovrebbe portarti lì.

In alternativa, se si controllano i siti client (i consumatori), è possibile aggiungere un qualificatore al proprio wrapper e utilizzare qualificatori per forzare le corrette implementazioni ai consumatori. Il wrapper potrebbe utilizzare l'implemementation non qualificato per ottenere l'accesso all'originale. (Potrebbe anche essere possibile montare a posteriori un qualificatore all'implementazione originale aggiungendo un'altra definizione di bean per il servizio con un qualificatore nel codice xml che controlli, non averlo provato ma dovrebbe funzionare)

Problemi correlati