Given an interface with a @Cacheable
method and an implementing component:
interface SomeComponent {
@Cacheable(cacheNames = "something")
int calculateSomething();
}
@Component
class SomeComponentImpl implements SomeComponent {
@Override
public int calculateSomething() {
return 0;
}
}
When using @EnableCaching
with its default values:
@Configuration
@EnableCaching // (mode = AdviceMode.PROXY, proxyTargetClass = false)
class CacheConfig {
@Bean
CacheManager cacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(singletonList(new ConcurrentMapCache("something")));
return cacheManager;
}
}
Then Spring does not create a bean of type SomeComponentImpl
and does not fail on startup. For example:
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(CacheConfig.class, SomeComponentImpl.class)) {
SomeComponent someComponent = context.getBean(SomeComponentImpl.class);
someComponent.calculateSomething();
}
fails with
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'example.SomeComponentImpl' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:371)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:362)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1268)
Removing the @Cacheable
annotation from the interface method or setting proxyTargetClass = true
fixes this specific issue.
Affected versions: 5.3.37, 6.0.22 6.1.10, 6.2.0-M4
Comment From: jhoeller
This is by design: Without proxyTargetClass, you'll get an interface-based proxy for any such use of @Cacheable
- and that kind of proxy cannot be cast to SomeComponentImpl
. It should work fine with getBean(SomeComponent.class)
instead, asking for the interface.