簡體   English   中英

在@PostConstruct期間使用@Cacheable的Spring緩存不起作用

[英]Spring cache using @Cacheable during @PostConstruct does not work

與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個框架按預期)

我的問題是:“這是一個安全的解決方法,因為初始提交者似乎只有使用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);

其中getRawBundleCacheable方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM