2015-02-05 105 views
5

在Spring框架涉及提交https://github.com/spring-projects/spring-framework/commit/5aefcc802ef05abc51bbfbeb4a78b3032ff9eee3春緩存不起作用

初始化設置爲後一階段從的afterPropertiesSet()afterSingletonsInstantiated()

簡而言之: 這可以防止在@PostConstruct用例中使用它時緩存工作。

加長版: 這可防止使用情況下,你會

  1. 上的methodB創建@Cacheable serviceB

  2. 創建@PostConstruct調用serviceB.methodB

    serviceA
    @Component 
    public class ServiceA{ 
    
    @Autowired 
    private ServiceB serviceB; 
    
    @PostConstruct 
    public void init() { 
        List<String> list = serviceB.loadSomething(); 
    } 
    

這會導致org.springframework.cache.interceptor.CacheAspectSupport現在不被初始化,因此不會緩存結果。

protected Object execute(CacheOperationInvoker invoker, Object target, Method method, Object[] args) { 
    // check whether aspect is enabled 
    // to cope with cases where the AJ is pulled in automatically 
    if (this.initialized) { 
//>>>>>>>>>>>> NOT Being called 
     Class<?> targetClass = getTargetClass(target); 
     Collection<CacheOperation> operations = getCacheOperationSource().getCacheOperations(method, targetClass); 
     if (!CollectionUtils.isEmpty(operations)) { 
     return execute(invoker, new CacheOperationContexts(operations, method, args, target, targetClass)); 
     } 
    } 
//>>>>>>>>>>>> Being called 
    return invoker.invoke(); 
} 

我的解決方法是手動調用初始化方法:

@Configuration 
public class SomeConfigClass{ 

    @Inject 
    private CacheInterceptor cacheInterceptor; 

    @PostConstruct 
    public void init() { 
    cacheInterceptor.afterSingletonsInstantiated(); 
    } 

當然,這解決了我的問題,但它有其他的副作用,只是被稱爲2倍(1本說明書和1個由框架意)

我的問題是: 「這是一個安全的解決方法做作爲初始commiter似乎有一個問題,只需使用的afterPropertiesSet()」

+0

代碼中的'@ PostConstruct'沒有給出保證代理已創建(也就是同樣的道理,爲什麼'@ Transactional'不會爲'@ PostConstruct'方法的工作。'@ PostConstruct'方法在構建之後和注入依賴之後立即調用,但幾乎總是在代理創建之前調用。你爲什麼需要'@ PostConstruct'方法?一般來說'ApplicationListener '是實現'SmartInitializingSingleton'接口而不是'@ PostConstruct'的好方法。 – 2015-02-05 20:23:51

+0

謝謝你的回覆。我們使用postconstruct來使用從另一個服務(其方法上有@Cacheable)取得的值初始化一個bean。我們期望即使在使用postconstruct時這些值也會被緩存。如果情況並非如此,那麼java文檔將會使框架受益,因爲其他開發人員可能也不會意識到這一點。將嘗試使用SmartInitializingSingleton。謝謝! – user2966436 2015-02-06 22:23:26

+0

這在[參考指南]中進行了解釋(http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-factory-lifecycle-default-init-destroy-methods)閱讀該部分的最後一段。 – 2015-02-08 14:40:37

回答

3

正如Marten所說,您不應該在PostConstruct階段使用任何這些服務,因爲您無法保證代理攔截器在此時已完全啓動。

預加載緩存的最佳方法是聽取ContextRefreshedEvent(更多支持來自4.2)並在那裏進行工作。這就是說,我知道可能不清楚這種用法是否被禁止,所以我創建了SPR-12700來改進文檔。我不確定你指的是什麼javadoc。

要回答你的問題:不,這不是一個安全的解決方法。你在使用「副作用」之前所使用的東西(即它不應該工作,如果你的bean在CacheInterceptor之前被初始化,那麼你將會有與老版本的框架相同的問題)。不要在您自己的代碼中調用這樣的底層基礎架構。

2

剛剛有與OP完全相同的問題,並且正在監聽ContextRefreshedEvent正在導致我的初始化方法被調用兩次。聽ApplicationReadyEvent最適合我。 下面是我用

@Component 
public class MyInitializer implements ApplicationListener<ApplicationReadyEvent> { 
    @Override 
    public void onApplicationEvent(ApplicationReadyEvent event) { 
     //doing things 
    } 
}