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.