2010-04-26 17 views
23

que tienen un comportamiento extraño cuando Autowiring@Autowire extraño problema

Tengo un código similar como éste, y funciona

@Controller 
public class Class1 { 
    @Autowired 
    private Class2 object2; 
    ... 
} 

@Service 
@Transactional 
public class Class2{ 
    ... 
} 

El problema es que necesito que la Clase 2 implementa una interfaz de modo Sólo he cambiado la Clase 2 por lo que es ahora como:

@Controller 
public class Class1 { 
    @Autowired 
    private Class2 object2; 
    ... 
} 

@Service 
@Transactional 
public class Class2 implements IServiceReference<Class3, Long>{ 
    ... 
} 

public interface IServiceReference<T, PK extends Serializable> { 
    public T reference(PK id); 
} 

con este código consigo un org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type for Class2. Parece que la anotación @Transitional no es compatible con la interfaz porque si elimino la anotación @Transitional o el i mplements IServiceReference<Class3, Long> el problema desaparece y se inyecta el bean (aunque necesito tener ambos en esta clase). También sucede si pongo la anotación @Transitional en los métodos en lugar de en la Clase.

Uso Spring 3.0.2 si esto ayuda.

¿No es compatible la interfaz con el método transaccional? ¿Puede ser un error de primavera?

Respuesta

28

El problema es que su Clase 1 necesita una referencia al IServiceReference y no la referencia concreta de la clase 2

@Controller 
public class Class1 { 
@Autowired 
private IServiceReference object2; 
    ... 
} 

La razón de esto es que la primavera es la creación de un proxy dinámico para las clases que se han marcado @Transactional. Por lo tanto, cuando se crea Class2 se envuelve en un objeto Proxy que obviamente no es del tipo Class2 sino que es del tipo IServiceReference.

Si desea que el comportamiento de uso de clase 2 con soporte de proxy, tendrá que activar el CGLIB Lea a continuación:

de manantiales Doc:

defecto primavera AOP para el uso de proxies dinámicos J2SE estándar para proxies AOP. Esto permite que cualquier interfaz (o conjunto de interfaces ) sea proxiada.

Spring AOP también puede usar proxies CGLIB. Esto es necesario para las clases proxy, en lugar de interfaces. CGLIB se usa de forma predeterminada si un objeto comercial no implementa una interfaz . Como es una buena práctica programar las interfaces en lugar de las clases, las clases de negocios normalmente implementarán una o más interfaces comerciales . Es posible fuerza el uso de CGLIB, en aquellos casos (con suerte raras) donde se necesita para asesorar a un método que no se declaró en una interfaz, o donde necesidad de pasar un objeto proxy a un método como un tipo concreto.

Es importante comprender el hecho de que Spring AOP está basado en proxy. Consulte la sección titulada Sección 6.6.1, "Comprensión de los proxys AOP" para un examen completo de exactamente qué detalla esta implementación en realidad significa .

13

La anotación Transactional indica a Spring que genere objetos proxy alrededor de los beans anotados para implementar la semántica transaccional. El proxy generado implementará las mismas interfaces que el bean de destino. Entonces, si su bean objetivo implementa IServiceReference, también lo hará el proxy generado.

Si el bean de destino no tiene interfaces implementadas, entonces el proxy generado será en cambio una subclase de del tipo de bean de destino.

En su ejemplo original, el proxy transaccional será una subclase de Class2, porque Class2 no implementó interfaces. Cuando cambió Class2 para implementar IServiceReference, el proxy generado ya no se extendió Class2, y en su lugar implementó IServiceReference. Esto causó su ClassCastException.

El mejor enfoque para esta situación consiste en eliminar la referencia a partir de Class1 a Class2, y en lugar de hablar con Class2 puramente a través de sus interfaces. Class2 puede implementar tantas interfaces como desee, el proxy las implementará todas.

puede forzar a Spring a generar proxies de subclases independientemente de las interfaces, pero es una complejidad adicional, y recomendaría que no lo haga.

+5

Básicamente lo mismo que dije :) –

1

Se puede forzar a su representación mediante la adición de

@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS) 

ver también this documentation.

+0

Esto es exactamente lo que es necesario, cuando la interfaz implementada en realidad no se relaciona con el cableado de los componentes. Puede suceder que desee pasar dicho componente como parámetro en alguna parte, pero se escribe como la interfaz. Nada que ver con Spring. Si hay múltiples interfaces, no hay problema. Si solo hay uno, Spring es el trabajo para él, y este '@ Scope' corrige su fijación perfectamente. :-) – virgo47

Cuestiones relacionadas