Spring Boot cache
Several important concepts & cache annotation
Cache | Cache interface, which defines cache operations. Implementations include RedisCache, EhCacheCache, ConcurrentMapCache, etc |
---|---|
CacheManager | The Cache manager manages various Cache components |
@Cacheable | It is mainly for method configuration, and the results can be cached according to the request parameters of the method |
@CacheEvict | wipe cache |
@CachePut | Ensure that the method is called and that the result is cached |
@EnableCaching | Enable annotation based caching |
keyGenerator | key generation strategy when caching data |
serialize | value serialization policy when caching data |
Spring Boot cache annotation introduction
- @EnableCaching annotation
- @Cacheable annotation
- @CachePut annotation
- @CacheEvict annotation
- @Caching annotation
- @CacheConfig annotation
@EnableCaching
It is provided by the Spring framework. The Spring Boot framework inherits the annotation. The annotation needs to be configured on the class (usually on the project startup class in Spring Boot) to enable annotation based caching support
@Cacheable annotation
@Cacheable annotation is also provided by the Spring framework. It can act on classes or methods (usually used on data query methods) to cache and store method results.
@The execution order of Cacheable annotation is to query the cache first. If it is empty, query the method and cache the results; If there is data in the cache, the method query is not performed, but the cached data is used directly.
@Cacheable annotation (attribute)
Attribute name | explain |
---|---|
value/cacheNames | Specifies the name of the cache space. Required attribute. Use one of these two attributes |
key | Specify the key of the cached data. By default, the method parameter value is used. You can use the SpEL expression |
keyGenerator | Specifies the generator of the key for caching data, which can be used with one of the key attributes |
cacheManager | Specify cache manager |
cacheResolver | Specifies the cache parser, which can be used with one of the cacheManager properties |
condition | Specifies data caching when certain conditions are met |
unless | Specifies that data caching will not be performed under certain conditions |
sync | Specifies whether to use asynchronous caching. Default false |
@Introduction to CachePut annotation
@CachePut annotation is provided by the Spring framework and can act on classes or methods (usually used on data update methods). The function of this annotation is to update cached data.
@The execution order of CachePut annotation is to call the method first, and then update the method result to the cache.
@The CachePut annotation also provides multiple attributes, which are exactly the same as those of the @ Cacheable annotation
@Introduction to CacheEvict annotation
@CacheEvict annotation is provided by the Spring framework and can act on classes or methods (usually used on data deletion methods). The function of this annotation is to delete cached data.
@The default execution order of CacheEvict annotation is to make method calls first, and then clear the cache.
@CacheEvict annotation also provides multiple attributes, which are basically the same as those of @ Cacheable annotation. In addition, it also provides two special attributes allEntries and beforeInvocation
@CacheEvict annotation (attribute)
(1) allEntries property
The allEntries property indicates whether to clear all cached data in the specified cache space. The default value is false (that is, only the cached data corresponding to the specified key is deleted by default).
(2) beforeInvocation property
The beforeInvocation property indicates whether the cache is cleared before the method is executed. The default value is false (that is, the cache is cleared after the method is executed by default)
@Introduction to Caching annotation
@Caching annotation is used for data cache management of complex rules and can act on classes or methods. The @ caching annotation contains three attributes: Cacheable, put and evict, which correspond to @ Cacheable, @ CachePut and @ CacheEvict annotations respectively
@Caching annotation usage (sample code)
@Caching(cacheable={@Cacheable(cacheNames ="comment",key = "#id")}, put = {@CachePut(cacheNames = "comment",key = "#result.author")}) public Comment getComment(int comment_id){ return commentRepository.findById(comment_id).get(); }
Spring Cache + Redis implements caching
Spring Cache is an excellent caching component. Since Spring 3.1, annotation Cache support similar to @ Transactional annotation transactions is provided, and Cache abstraction is provided to facilitate switching between various underlying caches (such as redis)
@EnableCaching: Mark @ EnableCaching, enable caching, and configure Redis cache manager.
@The EnableCaching annotation triggers the post processor to check whether there are cache annotations in the public method of each Spring bean. If such a comment is found, a proxy is automatically created to intercept method calls and handle the corresponding cache behavior
1. Required dependencies
<!-- redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- spring2.X integrate redis what is needed common-pool2--> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.6.0</version> </dependency>
2. Configuration file
#redis configuration spring.redis.host=localhost spring.redis.port=6379 spring.redis.database= 0 spring.redis.timeout=1800000 #redis connection pool configuration spring.redis.lettuce.pool.max-active=20 spring.redis.lettuce.pool.max-wait=-1 #Maximum blocking waiting time (negative number means no limit) spring.redis.lettuce.pool.max-idle=5 spring.redis.lettuce.pool.min-idle=0
3. redis configuration class
@Configuration @EnableCaching public class RedisConfig { /** * Custom key rule * @return */ @Bean public KeyGenerator keyGenerator() { return new KeyGenerator() { @Override public Object generate(Object target, Method method, Object... params) { StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()); sb.append(method.getName()); for (Object obj : params) { sb.append(obj.toString()); } return sb.toString(); } }; } /** * Set RedisTemplate rules * @param redisConnectionFactory * @return */ /** * Define your own redisTemplate object. If there is a redisTemplate object in the container, * springboot The default redisTemplate object will not be injected, and the name attribute may not be specified. The method name must be redisTemplate * (The default name of the bean should be the method name. This mechanism can also exclude the spring boot injection (default redisTemplate) */ @Bean public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); //(take out the data serialization configuration) // Configure the problem that the json string cannot be converted into a java Bean when the template object is used to read the json string from the cache. If it is not configured, an exception will be thrown // (java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to // com.springboot.enty.Stu) //Solve the problem of abnormal query cache conversion ObjectMapper om = new ObjectMapper(); // Specify the fields to be serialized, field,get and set, and modifier range. ANY includes private and public om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); // Specify the type of serialized input. The class must be non final modified. Final modified classes, such as string and integer, will run exceptions om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); //Serial number key value redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); redisTemplate.afterPropertiesSet(); return redisTemplate; } /** * Set CacheManager cache rules * @param factory * @return */ /** * Customize the cache manager and inject RedisCacheManager (not provided by springboot by default), * The following cache manager configures the cache expiration time (if there are other requirements, you need to redefine the cache manager and specify the corresponding cache manager when using cache annotation) * The expiration time is only valid for those annotations of the Cache, such as (@ Cacheable, @ CachePut), which has nothing to do with the Cache added by the redisTemplate object * And the serialization setting of cache annotation access data */ @Bean public CacheManager cacheManager(RedisConnectionFactory factory) { RedisSerializer<String> redisSerializer = new StringRedisSerializer(); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); //(take out the data serialization configuration) // The configuration uses @ Cacheable(value="'stus'",key="'stu:1 '") annotation when reading from the cache for the second time // The json string cannot be converted into a java Bean when the data is not configured. If it is not configured, an exception will be thrown // (java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to // com.springboot.enty.Stu) //Solve the problem of abnormal query cache conversion ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); // Configure serialization (solve the problem of garbled code), and the expiration time is 600 seconds RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofSeconds(600)) .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer)) .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)) .disableCachingNullValues(); RedisCacheManager cacheManager = RedisCacheManager.builder(factory) .cacheDefaults(config) .build(); return cacheManager; } }
4. List two interfaces
/** * Query sub node (including data dictionary) * Use redis+spring cache to cache the data dictionary * @param id * @return */ @Cacheable(value = "dict",keyGenerator = "keyGenerator") @Override public List<Dict> findChlidData(Long id) { //1. Query by parent id List<Dict> dictList = baseMapper.selectList(new QueryWrapper<Dict>().eq("parent_id", id)); //2. Set hasChildren to each dict object in the list collection for (Dict dict : dictList) { Long dictId = dict.getId(); //2.1. Judge whether there is child node data boolean hasChildren = hasChildren(dictId); dict.setHasChildren(hasChildren); } return dictList; }
/** * Import data dictionary * Clear redis cache when importing data dictionary * @param file */ @CacheEvict(value = "dict",allEntries = true) @Override public void importData(MultipartFile file) { try { EasyExcel.read(file.getInputStream(),DictEeVo.class,new DictListener(baseMapper)).sheet().doRead(); } catch (IOException e) { e.printStackTrace(); } }