2010-08-26 10 views
8

ho una definizione di fagioli in primavera e la sua controparte di proxy che è pensato per essere usato ovunque:ApplicationContext.getBean (Classe Clazz) non va bene con i proxy

<bean name="my.Bean" class="org.springframework.aop.framework.ProxyFactoryBean" scope="prototype"> 
    <property name="proxyInterfaces" value="my.Interface"/> 
    <property name="target" ref="my.BeanTarget"/> 
    <property name="interceptorNames"> 
    <list> 
     <value>someInterceptor</value> 
    </list> 
    </property> 
</bean> 

<bean name="my.BeanTarget" class="my.InterfaceImpl" scope="prototype"> 
    <property name="foo" ref="bar"/> 
</bean> 

Tutto questo funziona bene; e nel mondo v3 pre-Spring stavo usando come

ApplicationContext ctx = ...; 
my.Interface foo = (my.Interface) ctx.getBean("my.Bean"); // cast is necessary 

a Spring 3 è stato possibile fare tipo le ricerche sicure, ad esempio:

my.Interface foo = ctx.getBean(my.Interface.class); 

Ancora una volta, questo funziona bene per i fagioli comuni, mentre per I bean proxy ottengono my.BeanTarget anziché my.Bean. Ho cercato di inline my.BeanTarget (come indicato nella documentazione primavera) per rendere più nascosto, ma tutto quello che ho trovato era

org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [my.Interface] is defined: expected single bean but found 0: 

Quindi è possibile utilizzare le ricerche di tipo fagioli sicuri con fagioli proxy e se sì - come?

+0

Hai davvero bisogno di interagire direttamente con il contesto? La maggior parte delle mie applicazioni hanno solo bisogno di riavviarlo e quindi tutto il resto viene gestito con l'integrazione delle dipendenze (che funziona per i bean con proxy). Ho fatto alcune cose del framework in cui ho avuto bisogno di accedere al contesto, ma, secondo la mia esperienza, era raro. – SteveD

+0

Il nostro sistema è abbastanza ampio e alcuni bit e classi non nascono in Spring (né possono essere), quindi devono usare beanFactory/appCtx per ottenere le dipendenze necessarie. – mindas

risposta

6

Il problema qui è il scope="prototype" sul ProxyFactoryBean.

Il contesto solo inizializzerà avidamente le definizioni dei bean singleton. I bean di scope non singleton sono inizializzati solo quando richiesto. Ciò significa che quando si chiede il contesto per i bean di un determinato tipo, il contesto non può inizializzare quei bean non singleton per chiedere loro il tipo, deve fare riferimento puramente alle informazioni nella definizione bean.

Nel caso di ProxyFactoryBean, il tipo di proxy generato è determinato dalla logica complessa che richiede che il bean sia completamente inizializzato. Senza tale inizializzazione, ProxyFactoryBean può segnalare solo il tipo di destinazione come null.

Non posso dire un modo per aggirare questo, tranne usare una definizione di bean singleton, o chiedere esplicitamente il bean per nome, ad es.

<bean id="my.Interface"> class="ProxyFactoryBean"... > 

e poi:

ctx.getBean(MyInterface.class.getName()); 

Qui, usiamo la convenzione dei nomi di fagioli di essere l'interfaccia attuano.

1

Non puoi fare my.Interface foo = ctx.getBean(my.Bean.class);?

2

Sembra la portata del proxy creato da ProxyFactoryBean occorre precisare utilizzando singleton proprietà invece di attributo scope:

<bean name="my.Bean" class="org.springframework.aop.framework.ProxyFactoryBean"> 
    <property name="singleton" value="false"/> 
    ... 
</bean> 

Questo risolto il problema quando fagiolo bersaglio è interna.

Quando si dispone di diversi fagioli di alto livello della stessa classe, è possibile utilizzare una ricerca type-safe da ID:

my.Interface foo = ctx.getBean("my.Bean", my.Interface.class); 
+0

Ho accettato questa risposta troppo velocemente. Si scopre che la proprietà singleton = false non è la stessa cosa di scope = prototype. Sono riuscito a ottenere i bean singleton racchiusi nei proxy di destinazione anche se è stato specificato singleton = false. la risposta di skaffman è in realtà più vicina alla verità. – mindas

+0

Qual è l'argomento della stringa in questo 'getBean (String, Class)'? Puoi spiegare per favore? – Freakyuser

+0

È un nome del bean richiesto nel contesto dell'applicazione. Corrisponde all'attributo 'id' o' name' nella configurazione XML. – axtavt

0

Poiché Spring funziona con le interfacce, nel contesto di aop, è possibile definire diversi set di interfacce e richiedere quello che ci si aspetta. In questo modo nessun cast sarà necessario per una vera classe, ma Spring gestirà le interfacce.

Supponiamo di disporre di attrezzi di classe A B. Si desidera eseguire il cast dalla A alla B, ma viene rifiutato poiché A è un proxy a causa di aop. Quindi rendere A implementa C e C estende B. C possiede i metodi necessari e C è un'interfaccia privata accessibile solo dal codice di implementazione. Infine chiedi alla molla di iniettare B o C in base alle tue aspettative.

PrivateItf executor = context.getBean(PrivateItf.class); 

questo modo, anche se la classe reale è un proxy, implementa la vostra interfaccia privata con tutto ciò che il vostro bisogno.

Problemi correlati