Springboot — cache usage principle and redis integration

Time:2020-6-24

Introduction to foreword and core concepts

preface

This article mainly introduces the principle of cache in springboot2. X and several main notes, as well as the steps of integrating redis as cache

Core concepts

Let’s first look at the function and relationship diagram of the core interface:

CachingProvider  Manage and create CacheManager. A cacheprovider can manage multiple cachemanagers

CacheManager  Manage and create caches, one CacheManager manages multiple caches

Cache  Structure similar to map, each cache has a unique name

Entry Structure similar to map, stored in cache as key value pairs

Expiry  Every entry in the cache has an expiration date, which will be deleted or updated when it expires

 


 

 

1、 Cache structure in springboot:

You need to know that springboot registers components with the container through xxxautoconfiguration

So just knowCacheAutoConfigurationWhat components are registered, we can start to analyze

Found added components

1. First, enter cacheautoconfiguration. You can see that it has imported cacheconfigurationimportselector. From its name, you can see that it is used to import cache configuration classes

 

2. Enter cacheconfigurationimportselector, which is a static internal class. There is only one selectimports method. At the end of the method, return the string array to our method and mark a breakpoint for testing

3. After executing the method in the second step, you can directly check the final return result and see that many xxxcacheconfigurations have been returned

4. Add debug = true to the configuration file
To know which cacheconfiguration is used, we can add debug = true in the configuration file to view the detailed log startup application. When searching for cacheconfiguration in the log, we will find that only simplecacheconfiguration is matched and the other xxxcacheconfiguration is did not Match conclusion: springboot uses simplecacheconfiguration as the cache configuration class by default
After finding the configuration class, you can quickly understand its structure by following the configuration class layer by layer
View cache structure
1. Enter the default configuration class simplecacheconfiguration and find that concurrentmapcachemanager is registered in the configuration class as CacheManager note: @ conditionalonmissingbean( CacheManager.class )Notes
When there is a CacheManager in the container, this configuration class will not take effect, and the CacheManager is created through the configuration class, that is, if other xxxcacheconfiguration is selected, other cachemanagers will be generated, and this configuration class will not take effect. This is also the reason why rediscacheconfiguration will be used automatically after we import redis starter

   

2. Entering concurrentmapcachemanager cachemap is exactly the cache structure managed by concurrentmapcachemanager

3. Through debugging, it is found that the cache implementation class here is concurrentmapcache, in which two properties, name is the name of cache, and store is used to store key value pairs


So far, the default cache structure of springboot has come out. Let’s take a look at the common annotations we need to implement the cache function and what they should pay attention to

 

 

2、 Some key notes

  1、@Cacheable

Mark on the method, and store the returned results of the method in the cache

You can specify cachename or value to set the name property of concurrentmapcache

You can also specify the keygenerator to formulate the rules for generating keys in the cache key value pair

    Default: name is the parameter passed in, and the value in the key value pair is the method return result

   2、@CachePut

Mark on the method, execute the method first, and then update the cache content with the value returned by the method

   3、@CacheEvict

Clear cache

   4、@Caching

For complex cache configuration, you can configure the above notes in it

   5、@CacheConfig

Label on the class, and uniformly configure the cache operations in the class

 

 

3、 How @ cacheable works

  Here are several important ways to show how @ cacheable works

The test method here will get the data of employee 1 from the database. Only @ cacheable is marked on the method

 

First query

1. The first important method: concu rrentMapCacheManager.getCache (string name) see the following figure for details

 In concurrentmapcachemanager, check if there is a cache named EMP in the cachemap

If it exists, the cache will be returned. If it does not exist, the name passed in will be used as the name of the cache to create and return

We don’t exist here, so create and return a cache named EMP

 

2. Since this is the first query, there must be no employee content in the cache,

So the next step is to execute the real query method and call the database operation

 

3. After returning the result, call the cache created previously, and call its put method to store the employee ID and employee information in the cache in the form of key value pairs

 

 

Second query

With the above query, the information of employee 1 has been cached

Now let’s see what happens when we query employee 1 again

 

1. First, go to the getcache method of concurrentmapcachemanager to find the cache

Because of the first operation, there is a cache named EMP in the cachemap, so the cache is returned directly

 

2. Next, call the lookup method of cache to find the value through the key

 

 

3. Then the method returns the found value, and it ends directly without calling the actual database operation

 

summary

At the first query, cache is created, then the method is invoked, and the return value of the method is finally stored in cache.

In this way, when finding the same content, you can get it directly from the cache without calling methods to operate the database to find it

 

 

4、 Integrate redis

1. Add the redis starter, and springboot will automatically identify and use rediscacheconfiguration. The specific reasons are mentioned above

org.springframework.boot
            spring-boot-starter-data-redis

2. Enable redis service (you can use docker)

3、Create a configuration class and configure rediscachemanager (configure attributes such as serial number method)

package com.tlj.cache.config;

import com.tlj.cache.bean.Department;
import com.tlj.cache.bean.Employee;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.redis.cache.CacheKeyPrefix;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;

import java.time.Duration;

@Configuration
public class RedisConfig {

//    @Bean
//    public RedisTemplate empRedisTemplate(
//            RedisConnectionFactory redisConnectionFactory){
//        RedisTemplate template=new RedisTemplate();
//        template.setConnectionFactory(redisConnectionFactory);
//        Jackson2JsonRedisSerializer redisSerializer=new Jackson2JsonRedisSerializer(Employee.class);
//        template.setDefaultSerializer(redisSerializer);
//        return template;
//    }

//    @Bean
//    public RedisCacheConfiguration redisCacheConfiguration(){
//        Jackson2JsonRedisSerializer Jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Employee.class);
//        RedisSerializationContext.SerializationPair pair = RedisSerializationContext.SerializationPair.fromSerializer(Jackson2JsonRedisSerializer);
//        return RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(pair);
//    }

    /**
     *Or skip rediscacheconfiguration to create rediscachemanager
     *(in the case of multiple managers, you can specify @ cacheconfig)
     * @param redisConnectionFactory
     * @return
     */
    @Primary // multiple managers need to be set
    @Bean
    public RedisCacheManager empCacheManager(RedisConnectionFactory redisConnectionFactory){
        //Initializing a rediscachewriter
        RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
        //Set the value serialization method of CacheManager to Jackson 2jsonredisserializer
        Jackson2JsonRedisSerializer Jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Employee.class);
        RedisSerializationContext.SerializationPair pair = RedisSerializationContext.SerializationPair.fromSerializer(Jackson2JsonRedisSerializer);
        RedisCacheConfiguration defaultCacheConfig=RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(pair);
        //Set the default expiration time to 30 seconds
        defaultCacheConfig.entryTtl(Duration.ofSeconds(30));
        //Initialize rediscachemanager
        RedisCacheManager cacheManager = new RedisCacheManager(redisCacheWriter, defaultCacheConfig);
        return cacheManager;
    }

    @Bean
    public RedisCacheManager deptCacheManager(RedisConnectionFactory redisConnectionFactory){
        //Initializing a rediscachewriter
        RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
        //Set the value serialization method of CacheManager to Jackson 2jsonredisserializer
        Jackson2JsonRedisSerializer Jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Department.class);
        RedisSerializationContext.SerializationPair pair = RedisSerializationContext.SerializationPair.fromSerializer(Jackson2JsonRedisSerializer);
        RedisCacheConfiguration defaultCacheConfig=RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(pair);
        //Set the default expiration time to 30 seconds
        defaultCacheConfig.entryTtl(Duration.ofSeconds(30));
        //Initialize rediscachemanager
        RedisCacheManager cacheManager = new RedisCacheManager(redisCacheWriter, defaultCacheConfig);
        return cacheManager;
    }
}

RedisConfig

4. Specify the corresponding rediscachemanager on the corresponding class, similar to the following figure