@Autowire extraño problema
-
01-10-2019 - |
Pregunta
Tengo un comportamiento extraño cuando Autowiring
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 así que 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 ya que si se quita la anotación @Transitional
o la implements IServiceReference<Class3, Long>
se inyecta el disapears problema y el frijol (aunque tengo que tener tanto en esta clase). También sucede si pongo la @Transitional
anotación en los métodos en lugar de en la Clase.
Yo uso Primavera 3.0.2 si esto ayuda.
No es compatible con la interfaz con el método transaccional? Que sea un error de Primavera?
Solución
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. Así, cuando se crea Class2 su envuelta en un objeto proxy que obviamente no es de tipo Class2 pero es de tipo IServiceReference.
Si desea que el comportamiento de uso de clase 2 con la ayuda del poder que tendrá que activar el CGLIB Lea a continuación:
A partir de resortes Doc:
Spring AOP utiliza de forma predeterminada estándar proxies dinámicos J2SE para servidores proxy AOP. Esto permite a cualquier interfaz (o conjunto de interfaces) para ser proxy.
Spring AOP también puede usar proxies CGLIB. Esto es necesario para clases de proxy, en lugar de las interfaces. CGLIB se usa por defecto si lo hace un objeto de negocio no implementar una interfaz. Como están las cosas buenas prácticas de programa para las interfaces en lugar de clases, las clases de negocios normalmente implementar uno o más interfaces de empresa. Es posible forzar el uso de CGLIB, en aquellos casos (con suerte raras) donde se necesita para asesorar a un método que no es declarado en una interfaz, o donde necesidad de pasar un objeto proxy a una método como un tipo concreto.
Es importante comprender el hecho de que Primavera AOP es basado en proxy. ver el sección titulada Sección 6.6.1, “proxies AOP entendimiento” para una examen detallado de exactamente lo este detalle de implementación realidad medios.
Otros consejos
La anotación Transactional
instruye primavera para generar objetos proxy alrededor de los granos anotados, para implementar la semántica transaccional. El proxy generado implementará las mismas interfaces como el bean destino. Así que si sus implementos de frijol objetivo IServiceReference
, entonces también lo hará el proxy generado.
Si el bean destino no tiene interfaces implementadas, entonces el proxy generado en su lugar ser un subclase del tipo bean destino.
En el ejemplo original, el proxy transaccional será una subclase de Class2
, porque Class2
implementado ninguna interfaz. Al cambiar Class2
para implementar IServiceReference
, el proxy generada ya no Class2
extendida, y IServiceReference
vez implementado. Esto causó su ClassCastException
.
El mejor enfoque para esta situación consiste en eliminar la referencia a partir de Class1
Class2
, y en lugar de hablar con Class2
puramente a través de sus interfaces. Class2
puede implementar tantas interfaces como quiera, el proxy implementará todos ellos.
puede La fuerza del muelle para generar proxies subclase independientemente de las interfaces, pero es una complejidad adicional, y se lo recomiendo en contra de ella.
Se puede forzar a su representación mediante la adición
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)