2012-08-13 16 views
6

Me encontré con un caso en el que el proxy AOP creado mediante @Cacheable rompe la inyección de dependencia en Spring 3.1.1. Aquí está mi escenario:@Cacheable breaks DependencyInjection

Tengo una interfaz y una clase que implementa esta interfaz usando @Cacheable en el método implementado.

Ejemplo interfaz:

public interface ImgService { 
    public byte[] getImage(String name); 
} 

ejemplo de implementación:

public class ImgServiceImpl implements ImgService { 

    @Cacheable(cacheName = "someCache") 
    public byte[] getImage(String name){//TODO}; 

    protected String someOtherMethod(){//}; 
} 

I también tienen que clases de prueba JUnit - uno que inyecta la interfaz y uno de la aplicación:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "classpath*:META-INF/spring.xml" }) 
public class ImgServiceTest { 

    @Inject 
    private ImgService; 
} 

y

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "classpath*:META-INF/spring.xml" }) 
public class ImgServiceImplTest { 

    @Inject 
    private ImgServiceImpl; 
} 

La inyección de dependencias para la interfaz funciona bien. Sin embargo, cuando llego a inyectar la implementación en la segunda clase de prueba, obtengo un "Falló la inyección de dependencias autoconectadas". Pude depurarlo y parece que ClassUtils.isAssignableValue() compara incorrectamente el tipo deseado con la clase de proxy. Se llama por DefaultListableBeanFactory. Lo que es aún más extraño es que si elimino la anotación @Cacheable del método implementado y lo agrego a algún otro método protegido/privado, la inyección de dependencia funciona bien de nuevo. ¿Es esto un error y cuál sería el enfoque correcto para manejar esta situación?

+0

Aquí está uno más buena referencia - http://blog.springsource.org/2012/05/23/understanding-proxy-usage-in-spring/ –

Respuesta

3

OK, así que aquí está la solución que se me ocurrió finalmente.He implementado un método sencillo que intenta extraer el objeto de destino desde el proxy basado en la implementación de la clase org.springframework.aop.framework.Advised:

@SuppressWarnings({"unchecked"}) 
public static <T> T getTargetObject(Object proxy, Class<T> targetClass) { 
    if (AopUtils.isJdkDynamicProxy(proxy)) { 
    try { 
     return (T) ((Advised)proxy).getTargetSource().getTarget(); 
    } catch (Exception e) { 
     return null; 
    } 
    } else { 
    return (T) proxy; 
    } 
} 

Mi clase de prueba aplicación ahora se ve así:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "classpath*:META-INF/spring.xml" }) 
public class ImgServiceImplTest { 

    @Inject 
    private ImgService imgService; 

    private ImgServiceImpl imgServiceImpl; 

    @PostConstruct 
    public void setUp() { 
     imgServiceImpl = getTargetObject(imgService, ImgServiceImpl.class); 
    } 


} 
10

No es un error, es un efecto secundario esperado del uso de proxies dinámicos JDK para la implementación de AOP.

Puesto que todas las llamadas al método cacheables de ImgServiceImpl debe pasar por el proxy dinámico de tipo ImgService, no hay manera de inyectar esta dependencia en un campo de tipo ImgServiceImpl.

Al mover @Cacheable-private o protected método, la inyección funciona porque @Cacheable no entra en vigor en este caso - sólo public métodos se pueden utilizar aconsejaron AOP basado en proxy.

Por lo tanto, debe declarar los campos para ser inyectados como ImgService, o configurar Spring para utilizar los proxies basados ​​en clase de destino en su lugar usando proxy-target-class = "true".

Otra opción más es configurar Spring para usar AspectJ-based AOP implementation (requiere tiempo de compilación o de tiempo de carga).

Es aplicable a todas las características basadas en AOP proporcionadas por Spring (transacciones, seguridad, ejecución asíncrona, caché, aspectos personalizados, etc.).

Consulte también:

+0

Gracias por la respuesta. Todavía me parece extraño que el método ClassUtils no maneje esto, ya que parece tomar no mucho más que una instrucción if. – kpentchev

Cuestiones relacionadas