Spring cache annotation @ Cacheable @ CacheEvit @ CachePut introduction

  • 2021-10-16 01:49:39
  • OfStack

Directory I. Project environment
1. Project dependencies
II. Introduction to cache annotations
1. @Cacheable
2. @CachePut
3. @CacheEvict
4. @Caching
5. What happens to the cache in case of an exception?
6. Test cases
7. Summary
III. Can't miss the source code and related knowledge points
0. Projects

In version 3.1, Spring provides a cache strategy based on annotations, which is still very silky in actual use. This article will briefly introduce several commonly used annotations, and small partners who need it can try 1

The main knowledge points of this paper are as follows:

@ Cacheable: If the cache exists, the cache is used; If it does not exist, the method is executed and the result is stuffed into the cache @ CacheEvit: Invalid cache @ CachePut: Update cache

I. Project environment

1. Project dependencies

This project is developed by SpringBoot 2.2. 1.RELEASE + maven 3.5. 3 + IDEA + redis 5.0
Open 1 web service for testing


<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
</dependencies>

Use default configuration all the way, redis native, port 6379, no password

II. Introduction to cache annotations

1. @Cacheable

This annotation is used to modify the method or class. When we access the method it modifies, we take priority to get it from the cache. If it exists in the cache, we directly get the cached value; When the cache does not exist, execute the method and write the result to the cache
This annotation has two core settings


 /**
  *  And  cacheNames  Effect equivalence 
  */
 @AliasFor("cacheNames")
 String[] value() default {};

 
 @AliasFor("value")
 String[] cacheNames() default {};

 /**
  *  Cache key
  */
 String key() default "";

cacheNames can be understood as the prefix of caching key, and can be the key variable cached by components; When key is not set, use method parameters to initialize. Note that key is an SpEL expression, so if you want to write a string, enclose it in single quotation marks

1 simple use posture


/**
 *  First, check from the cache, and then return the cached data directly; Otherwise, the method is executed and the result is cached 
 * <p>
 * redisKey: cacheNames + key  Composed  -->  Support SpEL
 * redisValue:  Return results 
 *
 * @param name
 * @return
 */
@Cacheable(cacheNames = "say", key = "'p_'+ #name")
public String sayHello(String name) {
    return "hello+" + name + "-->" + UUID.randomUUID().toString();
}

If our reference is yihuihui, then the cache key is say:: p_yihuihui

In addition to the above three configuration values, if you look at the @ Cacheable annotation source code, you can see that there is also condition setting, which means that it will not be written into the cache until the conditions it sets are met


/**
 *  Satisfy condition Criteria are written to the cache 
 *
 * @param age
 * @return
 */
@Cacheable(cacheNames = "condition", key = "#age", condition = "#age % 2 == 0")
public String setByCondition(int age) {
    return "condition:" + age + "-->" + UUID.randomUUID().toString();
}

In the above case, when age is even, it will be cached; Otherwise the cache is not written
Next is the unless parameter, which, as you can see from its name, means that it is not written to the cache until the condition is not met


/**
 * unless,  Write to cache when conditions are not met 
 *
 * @param age
 * @return
 */
@Cacheable(cacheNames = "unless", key = "#age", unless = "#age % 2 == 0")
public String setUnless(int age) {
    return "unless:" + age + "-->" + UUID.randomUUID().toString();
}

2. @CachePut

Writes the return result of the method to the cache whether the cache exists or not; Applicable to cache updates


/**
 *  Write to the cache whether the cache exists or not 
 *
 * @param age
 * @return
 */
@CachePut(cacheNames = "t4", key = "#age")
public String cachePut(int age) {
    return "t4:" + age + "-->" + UUID.randomUUID().toString();
}

3. @CacheEvict

This is what we understand as deleting cache


/**
 *  Failure cache 
 *
 * @param name
 * @return
 */
@CacheEvict(cacheNames = "say", key = "'p_'+ #name")
public String evict(String name) {
    return "evict+" + name + "-->" + UUID.randomUUID().toString();
}

4. @Caching

In actual work, we often encounter a scenario in which one data changes and multiple caches are updated. For this scenario, we can realize it through @ Caching


/**
 * caching Implement combination, add caches, and invalidate other caches 
 *
 * @param age
 * @return
 */
@Caching(cacheable = @Cacheable(cacheNames = "caching", key = "#age"), evict = @CacheEvict(cacheNames = "t4", key = "#age"))
public String caching(int age) {
    return "caching: " + age + "-->" + UUID.randomUUID().toString();
}

This above is the combination operation

Fetch data from the caching:: age cache, execute the method when it does not exist and write it to the cache; Invalid cache t4:: age

5. What happens to the cache in case of an exception?

The above several case are all normal scenarios. How does this cache behave when the method throws an exception?


/**
 *  Is it written to the cache when testing exceptions 
 *
 * @param age
 * @return
 */
@Cacheable(cacheNames = "exception", key = "#age")
@Cacheable(cacheNames = "say", key = "'p_yihuihui'")
public int exception(int age) {
    return 10 / age;
}

According to the measured results, when age==0, neither of the above caches will succeed

6. Test cases

Next, verify whether the cached annotation is identical to the one described above


@RestController
public class IndexRest {
    @Autowired
    private BasicDemo helloService;

    @GetMapping(path = {"", "/"})
    public String hello(String name) {
        return helloService.sayHello(name);
    }
}

The above one is mainly to verify the annotation of @ Cacheable. If the cache misses, the results returned each time should be different. However, when actually accessing, it will be found that the returned results are all the same


 /**
  *  And  cacheNames  Effect equivalence 
  */
 @AliasFor("cacheNames")
 String[] value() default {};

 
 @AliasFor("value")
 String[] cacheNames() default {};

 /**
  *  Cache key
  */
 String key() default "";

0

Failure cache


 /**
  *  And  cacheNames  Effect equivalence 
  */
 @AliasFor("cacheNames")
 String[] value() default {};

 
 @AliasFor("value")
 String[] cacheNames() default {};

 /**
  *  Cache key
  */
 String key() default "";

1

Failure cache, which needs to be used in conjunction with case above


 /**
  *  And  cacheNames  Effect equivalence 
  */
 @AliasFor("cacheNames")
 String[] value() default {};

 
 @AliasFor("value")
 String[] cacheNames() default {};

 /**
  *  Cache key
  */
 String key() default "";

2

The rest of the other related test classes are better understood, 1 and post the corresponding code


@GetMapping(path = "condition")
public String t1(int age) {
    return helloService.setByCondition(age);
}

@GetMapping(path = "unless")
public String t2(int age) {
    return helloService.setUnless(age);
}

@GetMapping(path = "exception")
public String exception(int age) {
    try {
        return String.valueOf(helloService.exception(age));
    } catch (Exception e) {
        return e.getMessage();
    }
}

@GetMapping(path = "cachePut")
public String cachePut(int age) {
    return helloService.cachePut(age);
}

7. Summary

Finally, manage several cache annotations provided by Spring under Summary 1

@ Cacheable: If the cache exists, take it from the cache; Otherwise, the method is executed and the returned result is written to the cache @ CacheEvit: Invalid cache @ CachePut: Update cache @ Caching: All annotation combinations

Although the above can meet the common cache usage scenarios, there is a very important point that is not explained. How should the cache expiration time be set? ? ?
How to set a different cache expiration time for each cache? See you in the next blog post. I am 1 gray. Welcome to pay attention to the public number 1 gray blog of Changcao

III. Can't miss the source code and related knowledge points

0. Projects

Engineering: https://github.com/liuyueyi/spring-boot-demo
Source: https://github.com/liuyueyi/spring-boot-demo/tree/master/spring-boot/125-cache-ano


Related articles: