Why does Spring execute @Cacheable keyGenerator 2 times for a single invocation of @Cacheable annotated method

MattG :

Why does Spring execute my custom @Cacheable keyGenerator twice for a single invocation of a method annotated @Cacheable, why not do it just once.

My KeyGenerator implementation

package com.example.demo;

import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.ArrayList;

/**
 * Custom key generator
 */
@Component(value = "customerKeyGenerator")
public class CustomerKeyGen implements KeyGenerator
{
    @Override
    public Object generate(Object target, Method method, Object... params)
    {
        System.out.println("Generating a key");
        ArrayList<String> customerNames = (ArrayList<String>) params[0];
        return customerNames.hashCode();
    }
}

My Method annotated with @Cacheable with custom keyGenerator

package com.example.demo;

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;

import java.util.ArrayList;

@Component
public class CustomerService {

    @Cacheable(value = "customersCache", keyGenerator = "customerKeyGenerator")
    public int getCountOfCustomers(ArrayList<String> customerNames) {
        return customerNames.size();
    }
}

Spring Rest Controller which invokes the method annotated with @Cacheable

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.ArrayList;

@Controller
public class CustomerController {
    @Autowired
    CustomerService customerService;

    @RequestMapping("/")
    @ResponseBody
    String home() {
        return "Hello World!";
    }

    @RequestMapping("/countCustomers")
    @ResponseBody
    String countCustomers() {
        ArrayList<String> customerNames = new ArrayList<>();
        customerNames.add("john");
        customerNames.add("bill");

        return "countOfCustomers=" + String.valueOf(customerService.getCountOfCustomers(customerNames));
    }
}

When I make a single invocation of the method annotated with @Cacheable with my custom keyGenerator, I see 2 executions in my log and dubugger of System.out.println("Generating a key");

Curl to trigger method call invocation

curl http://127.0.0.1:8080/countCustomers
 % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    18  100    18    0     0     18      0  0:00:01 --:--:--  0:00:01    
76countOfCustomers=2

Log I have the following setting in application properties to enable tracing of the cache

logging.level.org.springframework.cache=TRACE

...
2018-08-27 11:56:53.753  INFO 18756 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2018-08-27 11:56:53.757  INFO 18756 --- [           main] c.example.demo.TestCacheableApplication  : Started TestCacheableApplication in 3.543 seconds (JVM running for 5.137)
2018-08-27 11:56:58.411  INFO 18756 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring FrameworkServlet 'dispatcherServlet'
2018-08-27 11:56:58.411  INFO 18756 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization started
2018-08-27 11:56:58.446  INFO 18756 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 35 ms
Generating a key
2018-08-27 11:56:58.480 TRACE 18756 --- [nio-8080-exec-1] o.s.cache.interceptor.CacheInterceptor   : Computed cache key '104328221' for operation Builder[public int com.example.demo.CustomerService.getCountOfCustomers(java.util.ArrayList)] caches=[customersCache] | key='' | keyGenerator='customerKeyGenerator' | cacheManager='' | cacheResolver='' | condition='' | unless='' | sync='false'
2018-08-27 11:56:58.480 TRACE 18756 --- [nio-8080-exec-1] o.s.cache.interceptor.CacheInterceptor   : No cache entry for key '104328221' in cache(s) [customersCache]
Generating a key
2018-08-27 11:56:58.480 TRACE 18756 --- [nio-8080-exec-1] o.s.cache.interceptor.CacheInterceptor   : Computed cache key '104328221' for operation Builder[public int com.example.demo.CustomerService.getCountOfCustomers(java.util.ArrayList)] caches=[customersCache] | key='' | keyGenerator='customerKeyGenerator' | cacheManager='' | cacheResolver='' | condition='' | unless='' | sync='false'

Conceptually, I would have thought Spring would need to run the keyGenerator only once, use it firstly to lookup the cache, and if not found, when the method is complete, use that same key to put to the cache. So I don't understand why I see this running twice.

My issues with this:

  1. I am confused with how it works and why
  2. The logging and debugging become confusing
  3. Potential performance impact, even though keyGeneration implementation should be cheap, why do it multiple times.
MattG :

I think I know why, key is generated once for lookup in cache, and once for putting into the cache. Not sure why it works that way, but appears to be what is happening.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Java

Alternatives to @Cacheable with spring webflux

From Java

JUnit 5 does not execute method annotated with BeforeEach

From Java

Spring @Cacheable and @Async annotation

From Java

Spring cache logging on @Cacheable hit

From Java

What does Spring's @Cacheable do when placed on a method returning a list?

From Java

Does Spring @Cacheable block if accessed by more that 1 thread?

From Java

Unable to use Spring @Cacheable and @EnableCaching

From Java

Spring Cacheable vs CachePut?

From Java

spring 3.1 @Cacheable example

From Java

@Cacheable key on multiple method arguments

From Java

Spring @Cacheable for methods with same signature

From Java

Where are Spring cacheable objects stored?

From Java

Using Spring @Cacheable with @PostFilter

From Java

Does @Cacheable annotated methods execute when the actual data is modified?

From Java

Spring Cacheable not working with default key

From Java

Spring cacheable not synchronized

From Java

Why can't we use @Cacheable with static method in spring with ehcache?

From Java

Spring @Cacheable default TTL

From Dev

My @Cacheable seems to be ignored (Spring)

From Dev

Spring @Cacheable not caching

From Dev

spring @Cacheable clarification required on implementation

From Dev

how to specify more than one param in method for spring Cacheable key

From Dev

Spring Cacheable with Object

From Dev

Spring Data Redis NullPointerException with @Cacheable

From Dev

Spring @Cacheable annotation for same method in different service

From Dev

Issue with Spring Cacheable - Not injecting service

From Dev

Clearing cache from a method annotated with @Cacheable

From Dev

Static Analysis tool to catch self-invocation bypassing Spring cache @Cacheable method

From Dev

Cacheable Annotation in Spring Boot

Related Related

  1. 1

    Alternatives to @Cacheable with spring webflux

  2. 2

    JUnit 5 does not execute method annotated with BeforeEach

  3. 3

    Spring @Cacheable and @Async annotation

  4. 4

    Spring cache logging on @Cacheable hit

  5. 5

    What does Spring's @Cacheable do when placed on a method returning a list?

  6. 6

    Does Spring @Cacheable block if accessed by more that 1 thread?

  7. 7

    Unable to use Spring @Cacheable and @EnableCaching

  8. 8

    Spring Cacheable vs CachePut?

  9. 9

    spring 3.1 @Cacheable example

  10. 10

    @Cacheable key on multiple method arguments

  11. 11

    Spring @Cacheable for methods with same signature

  12. 12

    Where are Spring cacheable objects stored?

  13. 13

    Using Spring @Cacheable with @PostFilter

  14. 14

    Does @Cacheable annotated methods execute when the actual data is modified?

  15. 15

    Spring Cacheable not working with default key

  16. 16

    Spring cacheable not synchronized

  17. 17

    Why can't we use @Cacheable with static method in spring with ehcache?

  18. 18

    Spring @Cacheable default TTL

  19. 19

    My @Cacheable seems to be ignored (Spring)

  20. 20

    Spring @Cacheable not caching

  21. 21

    spring @Cacheable clarification required on implementation

  22. 22

    how to specify more than one param in method for spring Cacheable key

  23. 23

    Spring Cacheable with Object

  24. 24

    Spring Data Redis NullPointerException with @Cacheable

  25. 25

    Spring @Cacheable annotation for same method in different service

  26. 26

    Issue with Spring Cacheable - Not injecting service

  27. 27

    Clearing cache from a method annotated with @Cacheable

  28. 28

    Static Analysis tool to catch self-invocation bypassing Spring cache @Cacheable method

  29. 29

    Cacheable Annotation in Spring Boot

HotTag

Archive