Spring Cache @Cacheable - not working while calling from another method of the same bean
I believe this is how it works. From what I remember reading, there is a proxy class generated that intercepts all requests and responds with the cached value, but 'internal' calls within the same class will not get the cached value.
From https://code.google.com/p/ehcache-spring-annotations/wiki/UsingCacheable
Only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual cache interception at runtime even if the invoked method is marked with @Cacheable.
Since Spring 4.3 the problem could be solved using self-autowiring over @Resource
annotation:
@Component
@CacheConfig(cacheNames = "SphereClientFactoryCache")
public class CacheableSphereClientFactoryImpl implements SphereClientFactory {
/**
* 1. Self-autowired reference to proxified bean of this class.
*/
@Resource
private SphereClientFactory self;
@Override
@Cacheable(sync = true)
public SphereClient createSphereClient(@Nonnull TenantConfig tenantConfig) {
// 2. call cached method using self-bean
return self.createSphereClient(tenantConfig.getSphereClientConfig());
}
@Override
@Cacheable(sync = true)
public SphereClient createSphereClient(@Nonnull SphereClientConfig clientConfig) {
return CtpClientConfigurationUtils.createSphereClient(clientConfig);
}
}
The example below is what I use to hit the proxy from within the same bean, it is similar to @mario-eis' solution, but I find it a bit more readable (maybe it's not:-). Anyway, I like to keep the @Cacheable annotations at the service level:
@Service
@Transactional(readOnly=true)
public class SettingServiceImpl implements SettingService {
@Inject
private SettingRepository settingRepository;
@Inject
private ApplicationContext applicationContext;
@Override
@Cacheable("settingsCache")
public String findValue(String name) {
Setting setting = settingRepository.findOne(name);
if(setting == null){
return null;
}
return setting.getValue();
}
@Override
public Boolean findBoolean(String name) {
String value = getSpringProxy().findValue(name);
if (value == null) {
return null;
}
return Boolean.valueOf(value);
}
/**
* Use proxy to hit cache
*/
private SettingService getSpringProxy() {
return applicationContext.getBean(SettingService.class);
}
...
See also Starting new transaction in Spring bean