Why does Spring Cache @Cacheable not work when calling a method from the same bean?

Question

Why isn't Spring's @Cacheable annotation being respected when I call a cached method from another method within the same bean?

<cache:annotation-driven cache-manager="myCacheManager" />

<bean id="myCacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
    <property name="cacheManager" ref="myCache" />
</bean>

<bean id="myCache"
    class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:shared="true">
    <property name="configLocation" value="classpath:ehcache.xml"></property>
</bean>

<cache name="employeeData" maxElementsInMemory="100"/>

Answer

When using Spring's caching capability, particularly the @Cacheable annotation, developers sometimes encounter unexpected behavior when calling cached methods internally within the same bean. This issue arises because Spring's caching proxies can only intercept calls made through the proxy, not direct method calls made within the same object instance.

@Service
public class AService {
    @Autowired
    private AService self;  // Injecting the same service for proxy call

    @Cacheable("employeeData")
    public List<EmployeeData> getEmployeeData(Date date){
        System.out.println("Cache is not being used");
        // Actual method implementation...
    }

    public List<EmployeeEnrichedData> getEmployeeEnrichedData(Date date){
        return self.getEmployeeData(date); // Using proxy to call
    }
}

Causes

  • Spring AOP (Aspect-Oriented Programming) is used to create proxies around beans for caching purposes.
  • When a method annotated with @Cacheable is called from within the same class, it bypasses the proxy and invokes the method directly, hence no caching occurs.
  • The caching mechanism only applies to calls made through the Spring proxy and not to direct method invocations. This is a common pitfall for developers utilizing Spring's caching features.

Solutions

  • Avoid calling cached methods directly within the same class. Instead, consider splitting methods into different service classes or using another bean to handle the cached method call.
  • Utilize the `@Autowired` annotation to inject the same bean into another method within the class. This way, you can call the cached method through the proxy, allowing the cache to function correctly.
  • For instance, refactor the class as follows:
  • public class AService { @Autowired private AService self; // Inject the same service @Cacheable("employeeData") public List<EmployeeData> getEmployeeData(Date date){ System.out.println("Cache is not being used"); // ... implementation } public List<EmployeeEnrichedData> getEmployeeEnrichedData(Date date){ return self.getEmployeeData(date); // Call through proxy } }

Common Mistakes

Mistake: Directly calling the @Cacheable method from another method within the same class.

Solution: Use an injected reference to the same class to ensure the call goes through the proxy.

Mistake: Improper configuration of caching (or missing cache manager setup).

Solution: Ensure that the caching annotations and cache manager are appropriately configured in your Spring application context.

Helpers

  • Spring Cache
  • @Cacheable not working
  • method invocation in Spring
  • Spring caching issues
  • Spring AOP proxy
  • EhCache in Spring

Related Questions

⦿Why Is Omitting Curly Braces Considered Bad Practice in Programming?

Discover the reasons behind the programming communitys stance on omitting curly braces and learn best practices for maintaining clear code.

⦿String.valueOf() vs. Object.toString() in Java: Key Differences Explained

Discover the differences between String.valueOfObject and Object.toString in Java including usage code examples and best practices.

⦿How to Include Variables in Strings in Java Without Concatenation?

Discover methods to include variables in Java strings without using concatenation. Learn alternatives with examples for better readability.

⦿How to Identify the JAR File Containing a Class in Java

Learn how to find the JAR file for a specific Java class using CodeSource and ProtectionDomain.

⦿What is the Difference Between Apache Solr and Apache Lucene?

Learn the key differences between Apache Solr and Apache Lucene their purposes and how they work together for search functionalities.

⦿Understanding String Concatenation with Null Values in Java

Learn why concatenating null strings in Java does not throw a NullPointerException and how it results in null followed by your string.

⦿Understanding the Key Differences Between Ant and Maven for Java Build Automation

Explore the essential differences between Ant and Maven for Java project build automation including usage structure and best practices.

⦿How to Remove Leading and Trailing Double Quotes from a String in Java

Learn how to efficiently trim leading and trailing double quotes from a string in Java with clear examples and explanations.

⦿How to Mock and Assert a Thrown Exception Using Mockito in JUnit Tests?

Learn how to effectively mock a method to throw an exception in Mockito and assert it in JUnit tests with stepbystep examples.

⦿How to Properly Format a Date Using the New Date-Time API in Java

Learn how to format dates correctly with Javas new DateTime API while avoiding exceptions like UnsupportedTemporalTypeException.

© Copyright 2025 - CodingTechRoom.com