Detailed tutorial on Redis caching in the SpringBoot series

Introducing the use of caching in SpringBoot projects, let's start with an introduction to Spring's cache abstraction and JSR107. This blog is a note I made after learning Silicon Valley videos and referring to other blogs for learning purposes only. This blog will provide more detailed information about Spring's cache annotations, how to use them to implement caching in Springboot projects, and also how to reference them.Cache in Redis for learning reference only

@[toc]

1. Cache abstraction of Spring

1.1. Cache abstract definition

Spring has defined org.springframework.cache.Cache since 3.1 Unify different caching technologies with the org.springframework.cache.CacheManager interface; and support the use of Java Caching (JSR-107) annotations to simplify our cache development.Spring Cache is responsible for maintaining the abstraction layer only, and the implementation depends on your technical choice.Decoupling cache processing and caching techniques.

1.2. Important interfaces

  • Cache: Cache Abstract specification interface, cache implementations are RedisCache, EhCacheCache, ConcurrentMapCache, etc.
  • Cache Manager: Cache Manager, which manages the life cycle of a Cache

II. JSR107

2.1, JSR107 Core Interface

Java Caching (JSR-107) defines five core interfaces: CachingProvider, CacheManager, Cache, Entry, and Expiry.

  • CachingProvider: Create, configure, acquire, manage, and control multiple CacheManager s
  • CacheManager: Create, configure, acquire, manage, and control multiple uniquely named Caches that exist within the context of CacheManager.A CacheManager corresponds to only one CachingProvider
  • Cache: is managed by Cache Manager, which manages the life cycle of Cache. Cache exists in the context of Cache Manager and is a map-like data structure that temporarily stores key-indexed values.A Cache is owned by only one CacheManager
  • Entry: is a key-value pair stored in a Cache
  • Expiry: Each entry stored in a Cache has a defined expiration date.Once this time is exceeded, the entries will automatically expire, after which they will not be accessible, updated, and deleted.Cache validity can be set through ExpiryPolicy

2.2, JSR107 Diagram

Reference the illustration in the Silicon Valley video courseware:

3. Spring Cache Use

3.1. Introduction to Important Notes

Before you go through the example practice, give a brief introduction to the important cache annotations provided by Spring

  • @Cacheable: For method configurations, the results of a method can be cached based on its request parameters
  • @CacheEvict: Empty Cache
  • @CachePut: Calls methods and updates cached data
  • @EnableCaching: Turn on annotation-based caching
  • @Caching: Define complex caching rules

3.2. Environmental Preparation

ok, this blog is rewritten with a video example from Silicon Valley, illustrated with this classic example

Environmental preparation:

  • maven environment
  • IntelliJ IDEA Create two new tables:
DROP TABLE IF EXISTS `employee`;
CREATE TABLE `employee` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `lastName` varchar(255) DEFAULT NULL,
  `email` varchar(255) DEFAULT NULL,
  `gender` int(2) DEFAULT NULL,
  `d_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `department`;
CREATE TABLE `department` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `departmentName` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

3.3. Introducing the spring-boot-starter-cache module

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>

3.4. Key Note Example Practice

3.4.1,@EnableCaching

@EnableCaching turns on annotation-based caching


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@SpringBootApplication
@EnableCaching
public class SpringbootCacheApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootCacheApplication.class, args);
    }

}

3.4.2, @Cacheable comment

The role of the @Cacheable annotation, which was also outlined earlier, is primarily for method configuration, which caches the results based on the method's request parameters, and describes the main properties of the annotation

  • cacheNames/value: Specifies the name of the cache component as an array
  • Key: the key used for caching data, which determines that the cache can be specified with a unique key; eg: writing SpEL; #id, value of parameter id, #a0 (first parameter), #p0 (same meaning as a0), #root.args[0]
  • Generator for keyGenerator: key; the component id of the generator for key can be specified by itself (Note: key/keyGenerator: Use both; not both)
  • cacheManager: Specify the cache manager; or cacheResolver specifies the get parser
  • Condition: Cache only when conditions are specified; with the SpEl expression, eg:condition ='#a0>1': Cache only when the value of the first parameter is >1
  • Unless: denies caching; when unless specifies a condition that is true, the return value of the method will not be cached; eg:unless ='#a0!=2 ": If the value of the first parameter is not 2, the result is not cached;
  • sync: whether to use asynchronous mode
    @Cacheable(value = {"emp"}, /*keyGenerator = "myKeyGenerator",*/key = "#id",condition = "#a0>=1",unless = "#a0!=2")
    public Employee getEmp(Integer id) {
        Employee employee = this.employeeMapper.getEmpById(id);
        LOG.info("query{}No. Employee Data",id);
        return employee;
    }

Custom keyGenerators can also be used here, using the property keyGenerator = "myKeyGenerator"

Define a @Bean class to add KeyGenerator to the Spring container

@Configuration
public class CacheConfig {

    @Bean(value = {"myKeyGenerator"})
    public KeyGenerator keyGenerator(){
        return new KeyGenerator() {
            @Override
            public Object generate(Object target, Method method, Object... params) {
                return method.getName()+"["+ Arrays.asList(params).toString()+"]";
            }
        };
    }
}

3.4.3, @CachePut comment

The @CachePut comment is also a comment for caching, but there is a clear difference between caching and @Cacheable in that it calls the method and updates the cached data, i.e. updates the cache synchronously after performing a method operation. So this primary key is often used for updating operations and also for querying. There are many similar properties for the primary key and @Cacheable. See the @link @CachePut source code for details

 /**
     *  @CachePut: Call method and update cache data; update cache synchronously
     *  Modify data and update cache
     */
    @CachePut(value = {"emp"}, key = "#result.id")
    public Employee updateEmp(Employee employee){
        employeeMapper.updateEmp(employee);
        LOG.info("To update{}No. Employee Data",employee.getId());
        return employee;
    }

3.4.4, @CacheEvic comment

Main attributes:

  • key: specify the data to be cleared
  • allEntries = true: Specifies to clear all data in this cache
  • beforeInvocation = false: Default means cache cleanup is performed after method execution
  • beforeInvocation = true: Represents that the cache cleanup operation was performed before the method was run
    @CacheEvict(value = {"emp"}, beforeInvocation = true,key="#id")
    public void deleteEmp(Integer id){
        employeeMapper.deleteEmpById(id);
        //int i = 10/0;
    }

3.4.5, @Caching comment

@Caching is used to define complex caching rules that integrate @Cacheable with @CachePut

 // @Caching defines complex caching rules
    @Caching(
            cacheable = {
                    @Cacheable(/*value={"emp"},*/key = "#lastName")
            },
            put = {
                    @CachePut(/*value={"emp"},*/key = "#result.id"),
                    @CachePut(/*value={"emp"},*/key = "#result.email")
            }
    )
    public Employee getEmpByLastName(String lastName){
        return employeeMapper.getEmpByLastName(lastName);
    }

3.4.6, @CacheConfig annotation

The @CacheConfig annotation can be used to extract the public configuration of the cache, then added to the class, eg:@CacheConfig(cacheNames = {"emp"},cacheManager = "employeeCacheManager")

Appendix Extensions: SpEL Expression Usage

Cache SpEL available metadata

Name position describe Example
methodName root object Method name currently being invoked #root.methodname
method root object Method currently called #root.method.name
target root object Currently invoked target object instance #root.target
targetClass root object Class of the target object currently being invoked #root.targetClass
args root object Parameter list of currently invoked methods #root.args[0]
caches root object List of caches used by current method calls #root.caches[0].name
argument Name Execution context Parameters of the currently invoked method, such as findArtisan(Artisan artisan), can be obtained from #artsian.id #artsian.id
result Evaluation context Return value after method execution (only if the judgement after method execution is valid, such as beforeInvocation=false for unless cacheEvict) #result

4. Integrated Redis Cache

4.1. Environmental preparation

Based on the previous Spring caching environment, integrating redis introduces related configurations:

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
<dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

Switch cache mode to Redis:spring.cache.type=redis

4.2. Redis configuration class implementation

RedisTemplate Configuration

@Resource
    private LettuceConnectionFactory lettuceConnectionFactory;

    @Bean
    @Primary
    public RedisTemplate<Object,Object> redisTemplate(){
        RedisTemplate<Object,Object> redisTemplate = new RedisTemplate<Object, Object>();
        redisTemplate.setConnectionFactory(lettuceConnectionFactory);
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = this.initJacksonSerializer();
        // Set serialization rules for value and key
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

RedisCacheManager-related code can refer to the blog post, which already has a good encapsulation of the code, so this article does not copy the code

4.3, RestTemplate related operations

Use RestTemplate to manipulate redis

  • 1. redisTemplate.opsForValue(); //Action string
  • 2. redisTemplate.opsForHash(); //operation hash
  • 3. redisTemplate.opsForList(); //operation list
  • 4. redisTemplate.opsForSet(); //operation set
  • 5. redisTemplate.opsForZSet(); //ordered set of operations

4.4. Caching Business Test

@Autowired
    DepartmentMapper departmentMapper;

    @Qualifier("redisCacheManager")
    @Autowired
    RedisCacheManager redisCacheManager;

//      @Cacheable(cacheNames = "dept",cacheManager = "redisCacheManager")
//    public Department getDeptById(Integer id){
//        System.out.println("Query Department"+id);
//        Department department = departmentMapper.getDeptById(id);
//        return department;
//    }

    // Use the cache manager to get the cache and make api calls
   public Department getDeptById(Integer id){
        LOG.info("query id by{}Employee information for",id);

        //Get a cache
        Cache deptCache = redisCacheManager.getCache("dept");
        Department department = null;
        if(deptCache.get(id)==null){
            department = departmentMapper.getDeptById(id);
            deptCache.put(id,department);
        } else {
            SimpleValueWrapper valueWrapper = (SimpleValueWrapper) deptCache.get(id);
            department = (Department)valueWrapper.get();
        }

        return department;
    }

Of course, using the previous Spring primary key can also be cached. Reference Blog: Cache abstraction layer Spring cache real-time operations

Code sample download: github link

Keywords: Programming Spring Redis SpringBoot Java

Added by t3l on Tue, 21 Apr 2020 20:09:29 +0300