Use redis and springbootredis in spring boot
Many times, we will configure redis in springboot, but only a few configurations will be ready, so we can't know why. Here we will explain in detail
Assume that a springboot project has been successfully created.
Redis connection Factory
Step 1: add the springboot redis jar package
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId></dependency>
Then we write a configuration class and create a spring bean for the redis connection factory. (The Redis connection factory will generate a connection to the Redis Database Server)
@ Configurationpublic class RedisConfig {@ Bean public RedisConnectionFactory redisCF () {// if no parameter is set, the local port 6379 JedisConnectionFactory factory = new JedisConnectionFactory (); factory is connected by default. setPort (6379); factory. setHostName ("localhost"); return factory ;}}
Unit test to see how to use this factory Method
@ RunWith (SpringJUnit4ClassRunner. class) @ SpringBootTest (classes = Application. class) public class RedisTest {@ Autowired RedisConnectionFactory factory; @ Test public void testRedis () {// get a connection RedisConnection conn = factory. getConnection (); conn. set ("hello ". getBytes (), "world ". getBytes (); System. out. println (new String (conn. get ("hello ". getBytes ())));}}
Output result: world indicates that the connection has been obtained successfully and data is obtained and added to redis,
Template)
However, we found that the key and value added each time are of the byte array type (difficult to use), So spring brought us the redis template (template)
Spring Data Redis provides two templates:
RedisTemplate
StringRedisTemplate
First, create a RedisTemplate template class. The type key is String type and the value is Object type. (If both key and value are String type, we recommend that you use StringRedisTemplate)
@ Bean public RedisTemplate redisTemplate (RedisConnectionFactory factory) {// create a template class RedisTemplate <String, Object> template = new RedisTemplate <String, Object> (); // set the redis connection factory to the template class template. setConnectionFactory (factory); return template ;}
Unit Test
@Autowired RedisTemplate<String, Object> template; @Test public void testRedisTemplate(){ template.opsForValue().set("key1", "value1"); System.out.println(template.opsForValue().get("key1")); }
It is very convenient to get the result output value1.
If it is an operation set, it is also very convenient.
@ Test public void testRedisTemplateList () {Pruduct prud = new Pruduct (1, "shampoo", "100"); Pruduct prud2 = new Pruduct (2, "cleanser ", "200"); // Add the element template from the tail in sequence. opsForList (). rightPush ("pruduct", prud); template. opsForList (). rightPush ("pruduct", prud); // query index 0 to total number of items-1 index (that is, to find all items) List <Object> prodList = template. opsForList (). range ("pruduct", 0, template. opsForList (). size ("pruduct")-1); for (Object obj: prodList) {System. out. println (Pruduct) obj);} System. out. println ("product quantity:" + template. opsForList (). size ("pruduct "));}
Key and value serialization
When a piece of data is saved, both the key and value must be serialized into json data. when the data is obtained, it is serialized into an object. Both the key and value are serialized using the serializer, spring data redis provides multiple serializer
- GenericToStringSerializer: Use Spring conversion service for serialization;
- JacksonJsonRedisSerializer: use Jackson 1 to serialize the object to JSON;
- Jackson2JsonRedisSerializer: use Jackson 2 to serialize the object to JSON;
- JdkSerializationRedisSerializer: use Java for serialization;
- OxmSerializer: Use the Spring O/X ing orchestrator and the unmarshaler (marshaler and unmarshaler) to implement
- Current serialization for XML serialization;
- StringRedisSerializer: serializes keys and values of the String type.
RedisTemplate uses JdkSerializationRedisSerializer by default, which means that both the key and value are serialized through Java. StringRedisTemplate uses StringRedisSerializer by default.
For example, if RedisTemplate is used, we want to serialize the value of the Product type to JSON, and the key is of the String type. The setKeySerializer () and setValueSerializer () Methods of the RedisTemplate must be as follows:
@ Bean public RedisTemplate redisTemplate (RedisConnectionFactory factory) {// create a template class RedisTemplate <String, Object> template = new RedisTemplate <String, Object> (); // set the redis connection factory to the template class template. setConnectionFactory (factory); // set the serialization tool template of the key. setKeySerializer (new StringRedisSerializer (); // set the value serializer // use Jackson 2 to serialize the Object to JSON Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new serialize (Object. class); // convert json to object class. If this parameter is not set, json is converted to hashmap ObjectMapper om = new ObjectMapper (); om. setVisibility (PropertyAccessor. ALL, JsonAutoDetect. visibility. ANY); om. enableDefaultTyping (ObjectMapper. defaultTyping. NON_FINAL); jackson2JsonRedisSerializer. setObjectMapper (om); template. setValueSerializer (jackson2JsonRedisSerializer); return template ;}
At this point, you will certainly have a simple understanding of using redis for springboot.
Springboot caches a method to declare the cache manager
In some cases, we may have this requirement. When a user logs on, we will read all the user permissions, departments, and other information from the database. In addition, every time you refresh the page, you need to determine whether the user has this permission. If you constantly read and compute data from the database,
It is very performance-consuming, so we need to use the cache manager that spring boot brings to us at this time.
First, add@ EnableCachingThis annotation.
This annotation is discovered by spring, and an aspect is created and the pointcut of the Spring cache annotation is triggered ). Based on the annotations used and the cache status, this section retrieves data from the cache, adds the data to the cache, or removes a value from the cache. Next, we need to declare a cache manager bean. This function is
@ EnableCachingThe method of the cache manager is called when the cache manager is added or deleted.
/*** Declares that the cache manager will create an aspect and trigger the pointcut of the Spring cache annotation. * According to the annotations used by the class or method and the cache status, this section retrieves data from the cache, adds the data to the cache, or removes a value * @ return */@ Bean public RedisCacheManager cacheManager (RedisTemplate redisTemplate) from the cache) {return new RedisCacheManager (redisTemplate );}
Of course, besides RedisCacheManager, the cache manager has some other features. For example
ConcurrentMapCacheManager. This simple cache manager uses java. util. concurrent. ConcurrentHashMap as its cache storage. It is very simple, so it is a good choice for development, testing, or basic applications.
Add Cache
Next we add annotations in the controller layer method, and then start our project.
@ RequestMapping ("/getPrud") @ Cacheable ("prudCache") public Pruduct getPrud (@ RequestParam (required = true) String id) {System. out. println ("if it is not found for the second time, the cache is added"); return pruductDao. getPrud (Integer. parseInt (id ));}
The printed message is printed only once, indicating that a plane is triggered when the method is reached and the data in the cache is returned.
Of course, the @ Cacheable annotation can also be placed in the dao layer method, but an error is reported here. Integer cannot be converted to String because the parameter type of our dao layer method is int, the key type of RedisTemplate is String, which should be noted here.
Open the redis client and find that the key corresponding to redis is our parameter 1, which will cause problems. For example, if the parameter of other methods to be cached is also 1, it will be repeated. The value of this key will be customized later.
In addition to @ Cacheable, springboot also includes several other annotations for us.
Delete Cache
Use @ CacheEvict to identify the Cache during the delete operation.
@RequestMapping("/deletePrud") @CacheEvict("pruddeleteCache") public String deletePrud(@RequestParam(required=true)String id){ return "SUCCESS"; }
@ CachePut put the return value of this method into the cache. If we put a Pruduct object, it will take this object as the key, which is obviously not what we want. At this time, we need to customize our key.
Custom key
@ Cacheable and @ CachePut both have a key attribute that can replace the default key. It is calculated using an expression (Spel expression, which is provided by spring and is very simple.
For example, the following example stores the id of the returned object as the key (but the Pruduct id is of the int type, so you need to convert the number to the String type)
@RequestMapping("/savePrud") @CachePut(value="prudsaveCache",key="#result.id +''") public Pruduct savePrud(Pruduct prud){ return prud; }
Besides # result indicates the return value of the function, spring also brings us some other metadata.
Conditional Cache
By adding Spring cache annotations to the method, Spring creates a cache plane around this method. However, in some scenarios, we may want to disable the cache function.
@ Cacheable and @ CachePut provide two attributes for conditional Caching: unless and condition. Both attributes accept a SpEL expression. If the SpEL expression of the unless attribute is calculated
If it is true, the data returned by the cache method will not be stored in the cache. Similarly, if the SpEL expression of the condition attribute returns false, the cache of this method will be disabled.
On the surface, the unless and condition attributes do the same thing. However, there is a slight difference here.
The unless attribute can only prevent objects from being cached. However, when this method is called, the object will still be searched in the cache. If a matching value is found, the value will be returned.
In contrast, if the condition expression calculates false, the cache is disabled during this method call. That is to say, it will not go to the cache for search, and the return value will not be put into the cache.
@ RequestMapping ("/getPrud2") @ CachePut (value = "prudCache", unless = "# result. desc. contains ('nocache') ") public Pruduct getPrud2 (@ RequestParam (required = true) String id) {System. out. println ("if you go here, it indicates that the cache has not taken effect! "); Pruduct p = new Pruduct (Integer. parseInt (id)," name_nocache "+ id," nocache "); return p ;}
In the above Code, if the returned object desc contains a nocache string, no cache is performed.
Summary demo:
Use the class name, method name, And pruduct id as the key
@ RequestMapping ("/getPrud3") @ Cacheable (value = "prudCache", key = "Export root.tar getClass. getName () + # root. methodName + # id ") public Pruduct getPrud3 (@ RequestParam (required = true) String id) {System. out. println ("if it is not found for the second time, the cache is added"); return pruductDao. getPrud (Integer. parseInt (id ));}
Last note
# The Return Value of the result method cannot be used on @ Cacheable, but only on @ CachePut.
Springboot configuration upgrade is simplified
Of course, the above configuration is just for understanding the principle. In fact, it will be simpler to use. We have rewritten RedisConfig.
@ Configuration @ EnableCaching // enable public class RedisConfig extends cachingassumersupport {@ Bean public KeyGenerator keyGenerator () {return new KeyGenerator () {@ Override public Object generate (Object target, Method 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 () ;};}/ *** declares the cache manager. A cut point (pointcut) is created and Spring cache annotation is triggered) * Based on the annotation used by the class or method and the cache status, this section obtains data from the cache, add data to the cache or remove a value from the cache * @ return */@ Bean public RedisCacheManager cacheManager (RedisTemplate redisTemplate) {return new RedisCacheManager (redisTemplate );} @ Bean @ Primary public RedisTemplate redisTemplate (RedisConnectionFactory factory) {// create a template class RedisTemplate <String, Object> template = new RedisTemplate <String, Object> (); // set the redis connection factory to the template class template. setConnectionFactory (factory); // set the serialization tool template of the key. setKeySerializer (new StringRedisSerializer (); // set the value serializer // use Jackson 2 to serialize the Object to JSON Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new serialize (Object. class); // convert json to object class. If this parameter is not set, json is converted to hashmap ObjectMapper om = new ObjectMapper (); om. setVisibility (PropertyAccessor. ALL, JsonAutoDetect. visibility. ANY); om. enableDefaultTyping (ObjectMapper. defaultTyping. NON_FINAL); jackson2JsonRedisSerializer. setObjectMapper (om); template. setValueSerializer (jackson2JsonRedisSerializer); return template ;}}View Code
Then configure it under application. properties under resources
# REDIS (RedisProperties) # Redis database index (0 by default) spring. redis. database = 0 # Redis server address spring. redis. host = 127.0.0.1 # Redis server connection port spring. redis. port = 6379 # Redis server connection password (blank by default) spring. redis. password = # maximum number of connections in the connection pool (negative value indicates no limit) spring. redis. pool. max-active = 8 # maximum blocking wait time of the Connection Pool (negative value indicates no restriction) spring. redis. pool. max-wait =-1 # maximum idle connection spring in the connection pool. redis. pool. max-idle = 8 # minimum idle connection spring in the connection pool. redis. pool. min-idle = 0 # connection timeout (MS) spring. redis. timeout = 0View Code
We found that we did not register RedisConnectionFactory, because spring helped us read the application. properties file by default and registered a factorybean.
The keyGenerator method helps us to register a key generation rule, so we don't need to write spel expressions. Read class name + method name + parameter based on the reflection principle. But sometimes we need to combine spel.
Add @ Cacheable ("cachename") to the controller. Then, you can see that the key value is saved in redis and the key value is the name generated by keyGenerator.
Code github address