2012-08-13 14 views
6

Mi sono imbattuto in un caso in cui il proxy AOP creato utilizzando @Cacheable interrompe l'iniezione di dipendenza in Spring 3.1.1. Ecco il mio scenario:@ Interruzioni memorizzabili DependencyInjection

Ho un'interfaccia e una classe che implementano questa interfaccia utilizzando @Cacheable con il metodo implementato.

interfaccia Esempio:

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

attuazione Esempio:

public class ImgServiceImpl implements ImgService { 

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

    protected String someOtherMethod(){//}; 
} 

devo anche classi di test JUnit - uno che inietta l'interfaccia ed un'attuazione:

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

    @Inject 
    private ImgService; 
} 

e

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

    @Inject 
    private ImgServiceImpl; 
} 

L'iniezione di dipendenza per l'interfaccia funziona correttamente. Tuttavia, quando riesco a iniettare l'implementazione nella seconda classe di test, ottengo un valore "Iniezione delle dipendenze autowired non riuscite". Sono stato in grado di eseguire il debug e sembra che ClassUtils.isAssignableValue() compari erroneamente il tipo desiderato per la classe proxy. È chiamato da DefaultListableBeanFactory. Ciò che è ancora più strano è che se rimuovo l'annotazione @Cacheable dal metodo implementato e lo aggiungo ad un altro metodo protetto/privato, l'injection dependency funziona di nuovo bene. È un bug e quale sarebbe l'approccio corretto per gestire questa situazione?

+0

Ecco un altro buon riferimento - http://blog.springsource.org/2012/05/23/understanding-proxy-usage-in-spring/ –

risposta

3

OK, ecco la soluzione mi è venuta finalmente.Ho implementato un metodo semplice che tenta di estrarre l'oggetto di destinazione dal proxy in base alla sua implementazione della classe 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; 
    } 
} 

mia implementazione classe di test appare come segue:

@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

Non è un bug, è un effetto collaterale previsto dell'utilizzo di proxy dinamici JDK per l'implementazione AOP.

Poiché tutte le chiamate al metodo cacheable di ImgServiceImpl dovrebbe passare attraverso il proxy dinamica di tipo ImgService, non c'è modo per iniettare questa dipendenza in un campo di tipo ImgServiceImpl.

Quando si sposta @Cacheable-private o protected metodo, l'iniezione funziona perché @Cacheable non ha effetto in questo caso - solo public metodi possono essere avvertita con AOP basata su proxy.

Pertanto, è necessario dichiarare i campi da iniettare come ImgService oppure configurare Spring per utilizzare i proxy di classe di destinazione utilizzando invece proxy-target-class = "true".

Un'altra opzione è configurare Spring per l'utilizzo di AspectJ-based AOP implementation (richiede la compilazione in tempo reale o in tempo di caricamento).

È applicabile a tutte le funzionalità basate su AOP fornite da Spring (transazioni, sicurezza, esecuzione asincrona, cache, aspetti personalizzati, ecc.).

Consulta anche:

+0

Grazie per la risposta. Mi sembra ancora strano che il metodo ClassUtils non lo gestisca, in quanto sembra non richiedere molto più di un'istruzione if. – kpentchev

Problemi correlati