javaspringspring-bootspring-cachejcache

Why result in condition inside @Cacheable doesn't have any affect?


I have following method:

@Cacheable(value = "pow_cache", unless = "#pow==3",condition = "#val<5&&#result<100")
public Double pow(int val, int pow) throws InterruptedException {
    System.out.println(String.format("REAL invocation myService.pow(%s, %s)", val, pow));
    Thread.sleep(3000);
    return Math.pow(val, pow);
}

and following main:

@SpringBootApplication
@EnableCaching
public class Main {

    public static void main(String[] args) throws InterruptedException {
        ConfigurableApplicationContext context = SpringApplication.run(Main.class);
        MyService myService = context.getBean(MyService.class);
        invokePow(myService, 4, 4);

    }

    private static void invokePow(MyService myService, int val, int pow) throws InterruptedException {
        for (int i = 0; i < 2; i++) {
            System.out.println(String.format("invoke myService.pow(%s, %s)", val, pow));
            System.out.println(myService.pow(val, pow));
        }
    }
}

And I see following output:

invoke myService.pow(4, 4)
REAL invocation myService.pow(4, 4)
256.0
invoke myService.pow(4, 4)
256.0

So it means that result was cached but it is unexpected beacause of

condition = "#val<5&&#result<100"

result is 256 and 256<100 is false

What do I wrong ?


Solution

  • There is difference between condition and unless. Based on this

    public abstract String unless
    Spring Expression Language (SpEL) attribute used to veto method caching.
    Unlike condition(), this expression is evaluated after the method has been called and can therefore refer to the result. Default is "", meaning that caching is never vetoed.

    from spring doc 3.2.x you can use #result only in unless.

    You can try

    @Cacheable(value = "pow_cache", unless = "#pow==3||#result>100",condition = "#val<5")