Spring Boot cache management
Cache is an important component in distributed system, which mainly solves the problem of high concurrent access to database data. In actual development, especially when users visit large websites, it is particularly important to use cache in order to improve server access performance, reduce database pressure and improve user experience. Spring Boot provides good support for caching. This chapter will introduce the cache management of Spring Boot and complete the integration of Spring Boot and Redis cache middleware.
Spring Boot default cache management
Spring framework supports adding cache to applications transparently and managing the cache. The core of cache management is to apply the cache to the method of operating data, so as to reduce the number of operating data without causing any interference to the program itself. Spring Boot inherits the cache management function of the spring framework. By using the @ EnableCaching annotation to enable annotation based cache support, Spring Boot can start the automatic configuration of cache management.
Basic environment construction
The main purpose of using cache is to reduce the access pressure of the database and improve the user experience. Therefore, we will demonstrate the cache management of Spring Boot in combination with the access operation of the database. Let's build a basic environment to demonstrate Spring Boot cache management.
Prepare data
For simplicity, use the spring boot data database created in Chapter 3, which has two tables t_article and t_comment. Several test data are pre inserted into these two tables.
Create project
1) Create a Spring Boot project and introduce related Dependencies. Use Spring Initlaizr to create a Spring Boot project named chapter06. Add JPA dependency, MySQL dependency in SQL module and web dependency in web module in Dependencies dependency option.
2) Write the entity class corresponding to the database table. Create a package named com.example.chapter06.domain in Chapter06, and create a database table t under the package_ Comment write the corresponding entity class comment, and use JPA related annotations to configure the mapping relationship.
Comment.java
package com.example.chapter06.domain; import javax.persistence.*; @Entity(name = "t_comment") public class Comment { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String content; private String author; @Column(name = "a_id") private Integer aId; //Omit property getter and setter methods //Omit the toString() method }
3) Write Repository interface files for database operations. Create a package named com.exmaple.chapter06.repository in Chapter06, and create a Repository interface for operating Comment entity under the package. The interface inherits from JapRepository and contains a method updateComment() for modifying comments.
CommentRepository.java
package com.example.chapter06.Repository; import com.example.chapter06.domain.Comment; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.transaction.annotation.Transactional; public interface CommentRepository extends JpaRepository<Comment, Integer> { @Transactional @Modifying @Query("update t_comment c set c.author=?1 where c.id=?2") public int updateComment(String author,Integer id); }
4) Write business operation class Service files. Create a package named com.exmaple.chapter06.service in Chapter06, and create a Service entity class for Comment related business operations under the package.
package com.example.chapter06.service; import com.example.chapter06.Repository.CommentRepository; import com.example.chapter06.domain.Comment; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Optional; @Service public class CommentService { @Autowired private CommentRepository commentRepository; public Comment findById(int comment_id){ Optional<Comment>optional=commentRepository.findById(comment_id); if(optional.isPresent()){ return optional.get(); } return null; } public Comment updateComment(Comment comment){ commentRepository.updateComment(comment.getAuthor(),comment.getaId()); return comment; } public void deleteComment(int comment_id){ commentRepository.deleteById(comment_id); } }
A CommentService business operation class is customized to query, modify and delete Comment data using the injected CommentRepository instance object.
5) Write the Web access layer Controller file. Create a package named com.exmaple.chapter06.controller in Chapter06, and create a Controller entity class for Comment access control under the package.
CommentController.java
package com.example.chapter06.controller; import com.example.chapter06.domain.Comment; import com.example.chapter06.service.CommentService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; @RestController public class CommentController { private final CommentService commentService; @Autowired public CommentController(CommentService commentService) { this.commentService = commentService; } @GetMapping("/get/{id}") public Comment findById(@PathVariable("id") int comment_id){ return commentService.findById(comment_id); } @GetMapping("/update/{id}/{author}") public Comment updateComment(@PathVariable("id") int comment_id,@PathVariable("author") String author){ Comment comment=commentService.findById(comment_id); comment.setAuthor(author); return commentService.updateComment(comment); } @GetMapping("/delete/{id}") public void deleteComment(@PathVariable("id") int comment_id){ commentService.deleteComment(comment_id); } }
Write configuration file
application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/springbootdata?serverTimezone=UTC spring.datasource.username=root spring.datasource.password=root spring.jpa.show-sql=true
First, configure the MySQL connection, and then configure the SQL statement spring. JPA. Show SQL = true to display the operation, so as to facilitate the effect demonstration when opening the cache later.
Project testing
Start the chapter06 project. After the project is successfully started, access it in the browser
Query the user comment information with id 1. No matter how many times the browser refreshes and accesses the same user comment information, the query result of the page will display the same data. However, each time the browser refreshes, the console will output a new SQL statement.
This is because cache management is not enabled in the Spring Boot project. Without cache management, although the data in the data table has not changed, each query operation will access the database and execute the SQL statement. With the accumulation of time, the number of users in the system is increasing, and the data scale is becoming larger and larger. The operation of the database will directly affect the user experience. At this time, using cache is often a very good manual way to solve this problem.
Spring Boot default caching experience
On the basis of the previously built Web application, open the cache supported by Spring Boot by default and experience the use effect of Spring Boot default cache.
1) Use the @ EnableCaching annotation to enable annotation based caching support, which is usually added to the project startup class.
Chapter06Application.java
package com.example.chapter06; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching; @SpringBootApplication @EnableCaching //Enable Spring Boot annotation based cache management support public class Chapter06Application { public static void main(String[] args) { SpringApplication.run(Chapter06Application.class, args); } }
2) Use the @ Cacheable annotation to manage the cache of data operation methods. Mark the @ Cacheable annotation on the query method of the Service class to cache the query results.
package com.example.chapter06.service; import com.example.chapter06.Repository.CommentRepository; import com.example.chapter06.domain.Comment; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import java.util.Optional; @Cacheable(cacheNames = "comment") @Service public class CommentService { private final CommentRepository commentRepository; @Autowired public CommentService(CommentRepository commentRepository) { this.commentRepository = commentRepository; } public Comment findById(int comment_id){ Optional<Comment>optional=commentRepository.findById(comment_id); return optional.orElse(null); } public Comment updateComment(Comment comment){ commentRepository.updateComment(comment.getAuthor(),comment.getaId()); return comment; } public void deleteComment(int comment_id){ commentRepository.deleteById(comment_id); } }
In the above code, the query cache annotation @ Cacheable is added to the findById(int comment_id) method in the CommentService class. The annotation is used to store the query result comment in the namespace named comment in the Spring Boot default cache, and the only ID corresponding to the cache is the method parameter comment by default_ The value of the ID.
3) Spring Boot default cache test. Start the chapter06 project, visit the browser and refresh several times.
No matter how many times you refresh, there is only one query statement.
Spring Boot cache annotation introduction
@EnableCaching annotation
@EnableCaching is provided by the Spring framework. The Spring Boot framework inherits the annotation. The annotation needs to be configured on the class (in Spring Boot, through configuration on the project startup class) to enable annotation based caching support.
@Cacheable annotation
The Cacheable annotation is also provided by the Spring framework. It can act on classes or methods to cache and store the query results of methods@ 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.
Attribute name | explain |
---|---|
value/cacheNames | Specify the name of the cache space. Required attribute. Use one of these two properties |
key | Set the key of cached data. By default, the method parameter value is used. You can use SpEL expression |
keyGenerator | The generator of the key used to cache the data is selected from the key attribute. |
cacheManager | Specify cache manager |
cacheResolver | Specifies the cache parser, which can be used with one of the cacheManager properties |
condition | Specifies that data caching is performed 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 |
Next, we will explain the properties of @ Cacheable annotation in detail
1) value/cacheNames attribute
The value and cacheNames attributes have the same function. They are used to specify the namespace of the cache. You can specify multiple namespaces at the same time (for example, @ Cacheable(cacheable = ("comment1", "comment2")). If the annotation only configures one attribute of value or cacheNames, these two attribute names can be omitted.
2) key attribute
The key attribute is used to specify the unique flag corresponding to the cached data. By default, the method parameter value marked with annotation is used, or SpEL expression can be used. The essence of cached data is Map type data. Key is used to specify the unique ID and value is used to specify the cached data.
If the key attribute is not specified when caching data, the configuration class SimpleKeyGenerator provided by Spring Boot by default will generate the key value through the generateKey(Object... params) method parameter. By default, if the generatekey () method uses a parameter, the parameter value is the value of the key attribute; If the generateKey() method has no parameters, the key attribute is a SimpleKey [] object with empty parameters. If there are multiple parameters, the key attribute is a SimpleKey[Params1,[Params2]] object with parameters.
SpEL expressions and descriptions supported by Cache cache
name | position | describe | Example |
---|---|---|---|
methodName | root object | The name of the currently called method | #root.methodName |
method | root object | Currently called method | #root.method.name |
target | root object | Target object instance currently called | #root.target |
args | root object | Parameter list of the currently called method | #root.args[0] |
caches | root object | Cache list of the currently called method | #root.caches[0].name |
ArgumentName | Execution context | The currently called method parameters can be identified in the form of # parameter name or #a0, #p0 (0 indicates parameter index, starting from 0) | #comment_id,#a0,#p0 |
result | Execution context | The returned result after the current method is executed | #result |
3) keyGenerator property
The keyGenerator attribute is essentially the same as the key attribute. It is used to specify the key of cached data, but the keyGenerator attribute specifies not the specific key value, but the generator rule of the key value, in which the specified generator generates the specific key. When using, choose between the keyGenerator attribute and the key attribute.
4) cacheManager/cacheResolver properties
The cacheManager and cacheResolver attributes are used to specify the cache manager and cache resolver respectively. They are also used as one of two attributes. By default, they do not need to be configured. If there are multiple cache managers, you can use the two attributes to specify them respectively.
5) condition property
The condition attribute is used to store data conditionally and selectively. The query results will be cached only when the specified condition is true. You can use the SpEL expression to formulate the attribute value. For example, @ Cacheable(cacheNames = "comment", condition = "#comment_id > 10") represents the method parameter comment_ The result is cached only when the value of ID is greater than 10.
6) unless attribute
The function of the unless attribute is opposite to that of the condition attribute. When the specified condition is true, the return value of the method will not be cached. The unless property can be specified using a SpEL expression. For example, @ Cacheable(cacheNames = "comment", unless="#result==null") means that the result data will be cached and stored only if the query result is not empty.
7) sync properties
The sync property indicates whether asynchronous mode is used during data caching. The default value is false
CachePut annotation
@The CachePut annotation is provided by the Spring framework and can act on classes or methods (usually used on data update methods). The annotation is used to update cached data@ The execution order of CachePut annotation is to make a method call 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.
CacheEvict annotation
CacheEvict annotation is provided by the Spring framework. It can act on classes or methods (usually data deletion methods). The function of this annotation is to delete cached data@ The default execution order of CacheEvict annotations is to make method calls first, and then clear the cache.
@The CacheEvict annotation provides multiple attributes, which are basically the same as those of the @ Cacheable annotation. In addition, @ CacheEvict provides two additional special properties allEntrier and beforeinvasion
1) 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). For example, @ CacheEvict(cacheNames = "comment", allEntrier=true) means that all data in the cache space comment will be deleted after the method is executed.
2) beforInvocation property
Indicates whether to clear the cache before the method is executed. The default value is false (that is, the cache is cleared after the method is executed by default). For example, @ CacheEvict(cacheNames = "comment", beforinvation = true) indicates that the cache will be cleared before the method is executed.
It should be noted that if the beforeInvocation property of the @ CacheEvict annotation is set to true, there will be some disadvantages. For example, an exception occurs in the data deletion method, which will cause the actual data not to be deleted, but the cached data to be cleared in advance.
Caching annotation
If dealing with data Caching of complex rules, you can use the @ Caching annotation, which acts on classes or methods@ The Caching annotation contains Cacheable, put and evict attributes, which are equivalent to @ Cacheable, @ CachePut and @ CacheEvict.
@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(); }
In the above code, the query operation is performed according to the ID, and the queried Comment object is cached. As can be seen from the code, the scope of the @ Caching annotation is on the getComment() method, and the Cacheable and put attributes are used in the @ Caching annotation. The Cacheable and put attributes are nested, and the @ Cacheable and @ CachePut annotations are introduced. In the two annotations, the values of the key are cached using #id and @ result.author respectively.
CacheConfig annotation
@The CacheConfig annotation acts on the class. Note that it is used to manage the public properties in all methods using @ Cacheable, @ CachePut and @ CacheEvict annotations in the class. These public properties include cacheNames, keyGenerator, cacheManager and cacheResolver
@CacheConfig(cacheNames="comment") @Service public class CommentService{ @Autowired private CommentRepository commentRepository; @Cacheable public Comment findById(int comment_id){ Comment comment=commentRepository.findById(comment_id).get(); return comment; } }
In the above code, the @ CacheConfig annotation is marked on the CommentService class, and the cacheName attribute is used to set the same cache space to comment, so that the cacheName attribute can be omitted when using cache annotations on all methods in this class.
Note: if the @ CacheConfig annotation is used on the class to define an attribute, and the cache annotation is used in the class method to define the same attribute, the attribute value will be verified nearby, and the annotation on the method shall prevail.
Spring Boot integrated Redis cache implementation
Cache components supported by Spring Boot
In Spring Boot, the management and storage of data depends on the cache related org.springframework.cache.Cache and org.springframework.cache.CacheManager cache manager interfaces in the Spring framework. If a Bean component of type cacheManager or a cacheResolver cache parser named cacheResolver is not defined in the program, Spring Boot will try to select and enable the following cache components.
- Generic
- JCache(JSR-107)
- EhCache 2.x
- Hazelcast
- Infinispan
- Couchbase
- Redis
- Caffeine
- Simple
Above, we listed 9 supported cache components according to the loading order of Spring Boot cache components. After adding a cache management component to the project, the Spring Boot project will select and enable the corresponding cache manager. If multiple cache components are added to the project at the same time and no cache manager or cache parser is specified, Spring Boot will give priority to starting the specified cache components and performing cache management.
Previously, we explained that in the default cache management of Spring Boot, cache management can be realized without adding any cache management components. This is because after cache management is enabled, Spring Boot will find valid cache components in the order of the above list for cache management. If there are no cache components, the last Simple cache component will be used for management by default. The Simple cache component is the default cache management component of Spring Boot. By default, it uses the ConcurrentHashMap in memory for cache storage, so it can also realize cache management in memory without any third-party cache components.
Redis cache implementation based on annotation
1) Add Spring Data Redis dependent initiator. Add the Spring Data Redis dependent initiator in the pom.xml file of the chapter06 project.
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
2) Redis service connection configuration. When using a third-party cache component similar to redis for cache management, the cache data is not stored in memory like the default cache management of Spring Boot, but needs to be pre built into a data warehouse similar to redis service for cache storage. Therefore, you need to install and start redis service first. Configure the global profile.
spring.redis.host=127.0.0.1 spring.redis.port=6379 spring.redis.password=
3) Use @ Cacheable, @ CachePut, @ CacheEvict annotations to customize cache management. Modify the methods in the CommentService class, and customize cache management with @ Cacheable, @ CachePut, @ CacheEvict3 annotations to demonstrate the storage, update and deletion of data respectively.
CommentService.java
package com.example.chapter06.service; import com.example.chapter06.Repository.CommentRepository; import com.example.chapter06.domain.Comment; import net.bytebuddy.build.CachedReturnPlugin; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import java.util.Optional; @CacheConfig(cacheNames = "comment") @Service public class CommentService { private final CommentRepository commentRepository; @Autowired public CommentService(CommentRepository commentRepository) { this.commentRepository = commentRepository; } @Cacheable(unless = "#result==null") public Comment findById(int comment_id){ Optional<Comment>optional=commentRepository.findById(comment_id); return optional.orElse(null); } @CachePut(key = "result.id") public Comment updateComment(Comment comment){ commentRepository.updateComment(comment.getAuthor(),comment.getaId()); return comment; } @CacheEvict public void deleteComment(int comment_id){ commentRepository.deleteById(comment_id); } }
4) Redis query cache test based on annotation. Through the above operations, we have added redis cache dependency and redis service connection configuration in the project, and @ EnableCaching has been used to enable annotation based cache management in the project. Now we can directly start the project for cache test.
Start the chapter06 project. After the project is successfully started, click the browser“ http://localhost:8080/get/1 "When you query the user comment information with id 1, you will find that the browser data response is wrong, and an exception message appears on the console.
The corresponding SQL statement was executed when querying the user Comment information, but the IllegalArgumentException illegal parameter exception occurred during cache storage. The prompt message requires that the corresponding Comment entity class must be serialized.
5) Serialize the cache object. Through the previous exception error prompt, it is found that when caching and storing entity class objects, serialization must be implemented first (some basic data types do not need serialization because the serialization interface has been implemented by default). Otherwise, cache exceptions will occur, resulting in the inability of the program to execute normally. Next, we will improve the Comment class for cache storage and implement the Serializable serialization interface of JDK.
Comment.java
package com.example.chapter06.domain; import javax.persistence.*; import java.io.Serializable; @Entity(name = "t_comment") public class Comment implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String content; private String author; @Column(name = "a_id") private Integer aId; }
The user comment information found by executing findById() method is correctly stored in the namespace named comment in Redis cache. The unique identification key value of cached data is embodied in the string form of "namespace comment:: + parameter value" (comment::1), while the value value is stored in HEX format formatted by JDK default sequence. This JDK default serialized data is obviously inconvenient for visual viewing and management of cached data, so in actual development, the serialization format of data is usually customized.
7) Redis cache update test based on annotation. First access through the browser“ http://localhost:8080/update/1/shitou ", the author of the comment with update id 1 is Shitou; Then continue the visit“ http://localhost:8080/get/1 ", query the user comment information with id 1.
8) Redis cache deletion test based on annotation.
#For Redis cache data based on annotation, the validity period is uniformly set to 1 minute, in milliseconds spring.cache.redis.time-to-live=60000
Redis cache implementation based on API
In the implementation of spring boot integrated Redis cache, in addition to the Redis cache implementation based on annotation, there is also a common way in development - Redis cache implementation based on API.
1) Redis API is used for business data cache management. On the basis of chapter06 project, write a business processing class ApiCommentService under the package com.example.chpater06.service
ApiCommentService.java
package com.example.chapter06.service; import com.example.chapter06.Repository.CommentRepository; import com.example.chapter06.domain.Comment; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import java.util.Optional; import java.util.concurrent.TimeUnit; @Service public class ApiCommentService { private final RedisTemplate<String,Comment> redisTemplate; private final CommentRepository commentRepository; @Autowired public ApiCommentService(RedisTemplate redisTemplate, CommentRepository commentRepository) { this.redisTemplate = redisTemplate; this.commentRepository = commentRepository; } public Comment findById(int comment_id){ Object object=redisTemplate.opsForValue().get("comment_"+comment_id); if(object!=null){ return (Comment) object; }else { Optional<Comment>optional= commentRepository.findById(comment_id); if(optional.isPresent()){ Comment comment=optional.get(); redisTemplate.opsForValue().set("comment_"+comment_id,comment,1, TimeUnit.DAYS); return comment; }else{ return null; } } } public Comment updateComment(Comment comment){ commentRepository.updateComment(comment.getAuthor(),comment.getaId()); redisTemplate.opsForValue().set("comment_"+comment.getId(),comment); return comment; } public void deleteComment(int comment_id){ commentRepository.deleteById(comment_id); redisTemplate.delete("comment_"+comment_id); } }
- RedisTemplate is a Java API provided by Spring Data Redis for direct Redis operation. It can be directly injected and used, which is simpler than the traditional Jedis.
- RedisTemplate can operate < object, Object > object type data, while its subclass StringRedisTemplate is specifically used for < string, string > string type data.
- RedisTemplate class provides many methods for data cache operations, such as data cache query, cache update, cache modification, cache deletion, and setting cache validity.
- redisTemplate.opsForValue().set("comment_" + comment_id, comment, 1, timeunit. Days ") sets the cache validity to 1 day while setting the cache data; Of course, you can set the cache validity and cache data.
redisTemplate.opsForValue().set("comment_"+comment_id,comment); redisTemplate.expire("comment_"+comment_id,90,TimeUnit,SECONDS);
2) Write the Web access layer Controller file.
ApiCommentController.java
package com.example.chapter06.controller; import com.example.chapter06.domain.Comment; import com.example.chapter06.service.ApiCommentService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/api") public class ApiCommentController { private final ApiCommentService apiCommentService; @Autowired public ApiCommentController(ApiCommentService apiCommentService) { this.apiCommentService = apiCommentService; } @GetMapping("/get/{id}") public Comment findById(@PathVariable("id") int comment_id){ return apiCommentService.findById(comment_id); } @GetMapping("/delete/{id}") public void deleteComment(@PathVariable("id") int comment_id){ apiCommentService.deleteComment(comment_id); } }
3) Related configurations of Redis cache implementation based on API. The API based Redis cache implementation does not require @ EnableCaching annotation to enable annotation based caching support, so you can choose to delete or annotate @ EnableCaching added to the project startup class.
In addition, the API based Redis cache implementation needs to introduce Redis dependent initiator into the pom.xml file of Spring Boot project, configure Redis service connection in the configuration file, and implement serialization interface for the COmment entity class for data storage. These Redis cache implementation steps configured in the solution are the same and have been implemented, which will not be repeated here.
In the Spring Boot project, after the API based Redis cache configuration is completed, you can test the cache query, cache update and cache deletion.
Compared with the annotation method, the Redis API is more flexible for cache management. For example, when the mobile phone verification code is used for verification, the verification waiting time can be set in the cache. Compared with using annotation for cache management, the amount of code written using Redis API may be more.
Customize Redis cache serialization mechanism
Customize RedisTemplate
Redis API default serialization mechanism
The Redis cache implementation based on Redis API uses the RedisTemplate template for data caching. Here, open the RedisTemplate class to view the source code
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperations<K, V>, BeanClassLoaderAware { //Various serialization methods of key and value are declared, and the initial value is null @Nullable private RedisSerializer keySerializer = null; @Nullable private RedisSerializer valueSerializer = null; @Nullable private RedisSerializer hashKeySerializer = null; @Nullable private RedisSerializer hashValueSerializer = null; ... //Set the default serialization method and set the JDK serialization method public void afterPropertiesSet() { super.afterPropertiesSet(); boolean defaultUsed = false; if (this.defaultSerializer == null) { this.defaultSerializer = new JdkSerializationRedisSerializer(this.classLoader != null ? this.classLoader : this.getClass().getClassLoader()); } ...
It can be seen from the above RedisTemplate core source code that various serialization methods of cache data key and value are declared in RedisTemplate, and the initial values are empty; In the afterpropertieset() method, if the serial number parameter defaultSerializer is null, the data serialization method is JdkSerializationRedisSerializer.
1) When RedisTemplate is used to cache Redis data, the internally used JdkSerializationRedisSerializer serialization method requires the serialized entity class to inherit the Serializable interface.
2) When RedisRemplate is used, if there is no special setting, the key and value are serialized using defaultSerializer=new JdkSerializationRedisSerializer().
In addition, in the RedisTemplate class source code, the various serialization types of cached data key and value are RedisSerializer. Enter the RedisSerializer source code to view the serialization methods supported by RedisSerializer.
It can be seen that RedisSerializer is a Redis serialization interface. By default, there are 6 implementation classes, which represent different data serialization methods in 6. Among them, JdkSerializationRedisSerializer comes with JDK and is also the default data serialization method used in RedisTemplate. We can choose other supported serialization methods as needed.
Customize RedisTemplate serialization mechanism
After Redis dependency is introduced into the project, the RedisAutoConfiguration automatic configuration provided by Spring Boot will take effect. Open the RedisAutoConfiguration class to view the definition method and core code of RedisTemplate in the internal source code.
public class RedisAutoConfiguration { @Bean @ConditionalOnMissingBean( name = {"redisTemplate"} ) @ConditionalOnSingleCandidate(RedisConnectionFactory.class) public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<Object, Object> template = new RedisTemplate(); template.setConnectionFactory(redisConnectionFactory); return template; } ... }
As can be seen from the above RedisAutoConfiguration core source code, in the Redis autoconfiguration class, a redistemplate is initialized through the RedisConnectionFactory; The @ ConditionalOnMissingBean annotation (as the name suggests, it takes effect when a Bean does not exist) is added above the redistemplate class to indicate that if a custom Bean named redistemplate is developed, the redistemplate will use the custom Bean.
If you want to use the redistemplate with custom serialization method for data caching, you can refer to the above core code to create a Bean component named redistemplate and set the corresponding serialization method in the component.
Next, we create a package named com.example.chapter06.config in the Chapter06 project, and create a Redis custom configuration class RedisConfig under the package.
package com.example.chapter06.Config; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; @Configuration public class RedisConfig { @Bean public RedisTemplate<Object,Object>redisTemplate(RedisConnectionFactory redisConnectionFactory){ RedisTemplate<Object,Object>template=new RedisTemplate<Object, Object>(); template.setConnectionFactory(redisConnectionFactory); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer=new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om=new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); template.setDefaultSerializer(jackson2JsonRedisSerializer); return template; } }
Use the @ Configuration annotation to label RedisConfig as a Configuration class, and use the @ Bean annotation to inject a component with the default name of redistemplate. In the Bean component, customize a redistemplate using the customized Jackson2JsonRedisSerializer data serialization method. In the customized serialization method, define an ObjectMapper for data conversion settings.
Effect test
Start the chapter06 project. After the project is successfully started, click the browser“ http://localhost:8080/api/get/3 "Query the user comment information with id 3, and repeatedly refresh the browser to view the same data information.
Customize RedisCacheManager
In Spring Boot 1.X, RedisCacheManager is built on the basis of RedisTemplate, while in spring boot 2. X, RedisCacheManager is built separately. Therefore, in Spring Boot2.X, after the RedisTemplate is built with a custom serialization mechanism, it is still impossible to override the default serialization mechanism inside RedisCacheManager (which explains why the annotation based Redis cache implementation will still use the JDK default serialization mechanism). You want to use the custom serialization mechanism for the annotation based Redis cache implementation, RedisCacheManager needs to be customized.
Customize RedisCacheManager
@Bean public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory){ //Create String and JSON format serialization objects respectively to convert the cached data key and value RedisSerializer<String>strSerializer=new StringRedisSerializer(); Jackson2JsonRedisSerializer jacksonSeial=new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om=new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL,JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jacksonSeial.setObjectMapper(om); RedisCacheConfiguration configuration=RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofDays(1)).serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(strSerializer)).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jacksonSeial)).disableCachingNullValues(); RedisCacheManager cacheManager=RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(configuration).build(); return cacheManager; }
In the above code, the @ Bean annotation is used in the RedisConfig configuration class to inject a cacheManager component with the default name of method name. In the defined Bean component, the key and value of cached data are customized in the serialization mode through RedisCacheConfiguration. The key of cached data is customized as stringredisserializer (i.e. String format), while the value is customized as jackson2jsonredisserializer (i.e. JSON format), and entryTtl(Duration.ofDays(1)) is also used Method sets the validity period of cached data to 1 day.