Spring cache using @Cacheable during @PostConstruct does not work

commit related in spring framework https://github.com/spring-projects/spring-framework/commit/5aefcc802ef05abc51bbfbeb4a78b3032ff9eee3

initialization is set to a later stage from afterPropertiesSet () to afterSingletonsInstantiated ()

In short : This prevents caching from being used when using @PostConstruct.

Longer version : This prevents use when you

  • create service B using @Cacheable on method B

  • create service A with a call to @ PostConstructB.methodB

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

This causes org.springframework.cache.interceptor.CacheAspectSupport not to initialize or cache the result.

 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(); } 

My workaround is to manually call the initialization method:

 @Configuration public class SomeConfigClass{ @Inject private CacheInterceptor cacheInterceptor; @PostConstruct public void init() { cacheInterceptor.afterSingletonsInstantiated(); } 

This, of course, fixes my problem, but does it have side effects, others that are simply called 2 times (1 manual and 1 for the intended purpose).

My question is: "Is this a safe workaround to do as the initial committer seems to have had a problem using the afterPropertiesSet () method"

+6
java spring-cache postconstruct
source share
3 answers

As Martin already said, you should not use any of these services during the PostConstruct stage, because you have no guarantee that the proxy interceptor is fully running at this point.

Your best way to preload the cache is to listen to ContextRefreshedEvent (more support in 4.2) and do the work there. However, I understand that it may not be clear that such use is prohibited, so I created the SPR-12700 to improve documentation. I'm not sure which javadoc you referenced.

To answer your question: no, this is not a safe workaround. What you used before worked with a "side effect" (that is, it should not have worked if your bean was initialized before CacheInterceptor , you would have the same problem with the old version of the framework). Do not name such a low-level infrastructure in your own code.

+5
source share

It just had the same problem as OP, and listening to ContextRefreshedEvent called my initialization method, which is called twice. Listening to ApplicationReadyEvent worked better for me. Here is the code I used

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

Automatically connect the ApplicationContext and call the method using:

 applicationContext.getBean(RBService.class).getRawBundle(bundleName, DEFAULT_REQUEST_LANG); 

where getRawBundle is the Cacheable method.

0
source share

All Articles