java - not - @Autowire extraño problema
configure autowired spring (3)
El problema es que su Class1 necesita una referencia a IServiceReference y no la referencia concreta de Class2
@Controller
public class Class1 {
@Autowired
private IServiceReference object2;
...
}
La razón es que Spring está creando un proxy dinámico para las clases que marcó @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 el comportamiento de usar Class2 con soporte de proxy, deberá encender CGLIB Lea a continuación:
De Springs Doc:
Spring AOP utiliza por defecto los proxies dinámicos J2SE estándar para los proxys 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 utiliza de manera predeterminada si un objeto comercial no implementa una interfaz. Como es una buena práctica programar interfaces en lugar de clases, las clases de negocios normalmente implementarán una o más interfaces de negocios. Es posible forzar el uso de CGLIB, en aquellos (afortunadamente raros) casos en los que necesita avisarle a un método que no está declarado en una interfaz, o donde necesita pasar un objeto por proxy a un método como un tipo concreto.
Es importante comprender el hecho de que Spring AOP se basa en un proxy. Consulte la sección titulada Sección 6.6.1, "Comprensión de los proxys de AOP" para un examen exhaustivo de lo que realmente significa este detalle de implementación.
Tengo un comportamiento extraño al autocablear
Tengo un código similar como este, y funciona
@Controller
public class Class1 {
@Autowired
private Class2 object2;
...
}
@Service
@Transactional
public class Class2{
...
}
El problema es que necesito que Class2 implemente una interfaz, así que solo cambié Class2, así que ahora es 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 obtengo una 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 @Transitional
anotación @Transitional
o los 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.
Yo uso Spring 3.0.2 si esto ayuda.
¿No es compatible la interfaz con el método transaccional? ¿Puede ser un error de primavera?
La anotación Transactional
instruye a Spring para 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á una subclase 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 extendió Class2
, y en su lugar implementó IServiceReference
. Esto causó su ClassCastException
.
El mejor enfoque para esta situación es eliminar la referencia de Class1
a Class2
, y en su lugar hablar con Class2
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.
Puede forzarlo a proxy agregando
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
también vea esta documentación .