2012-08-13 69 views
6

我偶然發現了使用@Cacheable創建的AOP代理在Spring 3.1.1中打破了依賴注入的情況。這是我的場景:@緩存中斷依賴注入

我有一個接口和一個類實現這個接口使用@Cacheable在實現的方法。

實施例接口:

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

實施例實現:

public class ImgServiceImpl implements ImgService { 

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

    protected String someOtherMethod(){//}; 
} 

我也有JUnit測試類, - 其中一個噴射接口和一個實現:

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

    @Inject 
    private ImgService; 
} 

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

    @Inject 
    private ImgServiceImpl; 
} 

接口的依賴注入工作正常。但是,當我開始在第二個測試類中注入實現時,我得到一個「注入自動裝載依賴關係失敗」。我能夠調試它,並且看起來ClassUtils.isAssignableValue()錯誤地將所需類型與代理類進行比較。它由DefaultListableBeanFactory調用。更奇怪的是,如果我從已實現的方法中刪除@Cacheable註釋並將其添加到其他protected/private方法,則依賴注入將再次正常工作。這是一個錯誤,處理這種情況的正確方法是什麼?

+0

這裏是一個更很好的參考 - http://blog.springsource.org/2012/05/23/understanding-proxy-usage-in-spring/ – 2012-08-13 15:41:24

回答

3

好了,這裏是我想出了最後的解決方案。我實現了試圖基於其執行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; 
    } 
} 

我實現測試類現在看起來是這樣的:

@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

這不是一個bug,它是使用JDK動態代理實現AOP的預期副作用。

由於所有對ImgServiceImpl可緩存方法的調用都應該通過類型爲ImgService的動態代理,因此無法將此依賴項注入ImgServiceImpl類型的字段。

當您移動@Cacheableprivateprotected法,注射工作,因爲@Cacheable不起作用在這種情況下 - 只有public方法可以使用基於代理的AOP被勸。

因此,您應該聲明要注入的字段爲ImgService,或配置Spring使用目標基於類的代理,而不是使用proxy-target-class = "true"

另一種選擇是將Spring配置爲使用AspectJ-based AOP implementation(需要編譯時或加載時編織)。

它適用於Spring提供的所有基於AOP的功能(事務,安全,異步執行,緩存,自定義方面等)。

參見:

+0

謝謝你的答案。我仍然覺得這個ClassUtils方法不能處理這個問題,因爲它看起來並不比if語句多得多。 – kpentchev 2012-08-13 17:02:17