![](/img/trans.png)
[英]Spring cache using @Cacheable not working on startup @PostConstruct
[英]Spring cache using @Cacheable during @PostConstruct does not work
與spring框架中的提交有關https://github.com/spring-projects/spring-framework/commit/5aefcc802ef05abc51bbfbeb4a78b3032ff9eee3
初始化設置為從afterPropertiesSet()到afterSingletonsInstantiated()的后續階段
簡而言之 :這可以防止在@PostConstruct用例中使用緩存時緩存工作。
更長的版本 :這可以防止您使用的用例
在methodB上使用@Cacheable創建serviceB
使用@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個框架按預期)
我的問題是:“這是一個安全的解決方法,因為初始提交者似乎只有使用afterPropertiesSet()的問題”
正如Marten已經說過的那樣,你不應該在PostConstruct
階段使用任何這些服務,因為你無法保證代理攔截器已經完全啟動了。
預加載緩存的最佳方法是監聽ContextRefreshedEvent
(4.2中的更多支持)並在那里完成工作。 話雖如此,我知道可能不清楚這種用法是否被禁止,所以我創建了SPR-12700來改進文檔。 我不確定你指的是什么javadoc。
回答你的問題:不,這不是一個安全的解決方法。 你之前使用的是“副作用”(即它不應該工作,如果你的bean在CacheInterceptor
之前被初始化,你會CacheInterceptor
與舊版本框架相同的問題)。 不要在自己的代碼中調用這樣的低級基礎結構。
剛剛遇到與OP完全相同的問題,並且監聽ContextRefreshedEvent
導致我的初始化方法被調用兩次。 聽ApplicationReadyEvent
為我工作最好的。 這是我使用的代碼
@Component
public class MyInitializer implements ApplicationListener<ApplicationReadyEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
//doing things
}
}
Autowire ApplicationContext
並使用以下方法調用方法調用:
applicationContext.getBean(RBService.class).getRawBundle(bundleName, DEFAULT_REQUEST_LANG);
其中getRawBundle
是Cacheable
方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.