2010-08-26 17 views
8

tengo una definición de frijol en primavera y su homólogo de proxy que está destinado a ser utilizado en todas partes:ApplicationContext.getBean (clazz Clase) no va bien con los proxies

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

Todo esto funciona bien; y en el mundo v3 pre-primavera lo estaba utilizando como

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

En primavera 3 se hizo posible realizar búsquedas seguras tipo, por ejemplo:

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

Una vez más, esto funciona bien para los granos ordinarios mientras que para Proxied beans Me estoy poniendo my.BeanTarget en lugar de my.Bean. He tratado de inline my.BeanTarget (como se muestra en la documentación de primavera) para que sea oculto, pero todo lo que me dieron fue

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

lo tanto, es posible utilizar las búsquedas de tipo de frijol seguras con granos de proxy y si es así - ¿cómo?

+0

¿Realmente necesita interactuar directamente con el contexto? La mayoría de mis aplicaciones solo necesitan arrancarlo y todo lo demás se maneja con inyección de dependencia (que funciona para beans proxies). He terminado algunas cosas sobre el framework donde necesitaba acceder al contexto, pero, en mi experiencia, era raro. – SteveD

+0

Nuestro sistema es bastante amplio y algunos bits y clases no nacen en Spring (ni puede serlo), por lo que deben usar beanFactory/appCtx para obtener las dependencias necesarias. – mindas

Respuesta

6

El problema aquí es la scope="prototype" en su ProxyFactoryBean.

El contexto solo inicializará ansiosamente las definiciones de bean singleton. Los beans de ámbito no único se inicializan solo cuando se solicitan. Esto significa que cuando se pregunta en el contexto por los beans de un tipo dado, el contexto no puede inicializar esos beans no únicos para preguntarles su tipo, sino que tiene que ir puramente a la información en la definición del bean.

En el caso de ProxyFactoryBean, el tipo del proxy generado se determina mediante lógica compleja que requiere que el bean se inicialice por completo. Sin esa inicialización, ProxyFactoryBean solo puede informar el tipo de destino como null.

No puedo decir una forma de evitar esto, que no sea usar una definición de bean singleton, o pedir explícitamente el bean por su nombre, por ej.

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

y luego:

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

Aquí, se utiliza la convención de nombres de frijol siendo la interfaz que implementan.

1

¿No puedes hacer my.Interface foo = ctx.getBean(my.Bean.class);?

2

Parece que el alcance de los poderes creados por ProxyFactoryBean debe especificarse utilizando singleton propiedad en lugar del atributo scope:

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

Esto resolvió el problema cuando frijol objetivo interno.

Cuando tiene varios granos de alto nivel de la misma clase, se puede utilizar una consulta de tipo seguro por id:

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

Acepté esta respuesta demasiado rápido. Resulta que la propiedad singleton = false no es lo mismo que scope = prototype. Logré obtener beans singleton que están envueltos en proxies de destino aunque se especificó singleton = false. La respuesta de skaffman en realidad está más cerca de la verdad. – mindas

+0

¿Cuál es el argumento de cadena en este 'getBean (String, Class)'? ¿Puede usted explicar por favor? – Freakyuser

+0

Es un nombre del bean solicitado en el contexto de la aplicación. Corresponde al atributo 'id' o' name' en la configuración XML. – axtavt

0

Como Spring funciona con Interfaces, en el contexto de aop, podría definir diferentes conjuntos de interfaces y solicitar el que espera. De esta forma, no se necesitará molde para una clase real, pero Spring administrará las interfaces.

Digamos que tiene implementos de Clase A B. Quiere lanzar A a B, pero se rechaza ya que A es un proxy debido a aop. Luego haga que A implemente C y C extienda B. C posee los métodos necesarios, y C es una interfaz privada a la que solo se accede desde su código de implementación. Finalmente, pida a Spring que inyecte B o C, según sus expectativas.

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

De esta manera, incluso si la clase real es un proxy, implementa su interfaz privada con todas sus necesidades.

Cuestiones relacionadas