繁体   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