From Spring Boot 2.x onwards Jedis has been replaced as the preferred Redis client. Of course, Spring Boot 2.x still supports Jedis, and you can switch clients at will.

Lettuce

Lettuce is a scalable thread-safe Redis client that supports synchronous, asynchronous and responsive modes. Multiple threads can share a connection instance without having to worry about multi-threaded concurrency. It is built on the excellent Netty NIO framework and supports advanced Redis features such as Sentinel, clustering, pipelining, automatic reconnection, and Redis data model

Jedis is implemented as a directly connected Redis Server. If it is not thread-safe in a multi-threaded environment, the only way to do this is to add physical connections to each Jedis instance using connection pooling.

The connection is Netty based, and StatefulRedisConnection can be accessed concurrently between multiple threads. The StatefulRedisConnection is thread-safe. Therefore, a StatefulRedisConnection can satisfy concurrent access in a multi-threaded environment. Of course, this is also a scalable design. If a connection instance is not enough, it can also be added as needed.

Spring Boot 2.0 integrates with Redis

It usually takes 4 steps

  1. Introduction of depend on
  2. Configure redis
  3. Custom RedisTemplate (recommended)
  4. Custom Redis action classes (recommended)

Introduction of depend on

<! --redis--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <! Commons -pool2</artifactId> Commons -pool2</artifactId> </dependency> <! --jackson--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </dependency>Copy the code
  • If you are using a lettuce client, you need to introduce commons-pool2 connection pool.
  • If you want to serialize redis values using JSON, you need to introduce Jackson

Configure redis

# redis.host=localhost # port=6379 # redis.port=6379 Default is null spring.redis. Password = # database used, Database =0 # client timeout, default is 2000ms spring.redis.timeout=2000ms ## Jedis client configuration (from Spring Boot 2.x In the beginning, it is no longer recommended to use jedis client) ## The maximum waiting time for establishing a connection is 1ms by default. A value of -1 indicates an infinite wait until allocation is successful. # spring. Redis. Jedis. Pool. Max - dalian wait = 1 ms # # the most number of connections, the default is 8, negative said there is no limit to the # spring. Redis. Jedis. Pool. The Max - active = 8 # # the largest number of idle connections, 8 by default. Negative said there is no limit to the # spring. Redis. Jedis. Pool. The Max - idle = 8 # # the minimum number of idle connections, the default is 0. # spring. Redis. Jedis. Pool. Min - idle = 0 # lettuce client configuration (from spring Boot 2 x, it is recommended to use lettuce client) # connect maximum wait time, default 1 ms, beyond the time will throw exceptions. A value of -1 indicates an infinite wait until allocation is successful. Spring. Redis. Lettuce. Pool. Max - wait = # 1 ms dalian the most number of connections, the default is 8, negative said there is no limit to the spring. Redis. Lettuce. The pool. The Max - active = 8 # maximum number of idle connections, 8 by default. Negative said there is no limit to the spring. Redis. Lettuce. The pool. The Max - idle = 8 # minimum number of idle connections, the default is 0. Spring. Redis. Lettuce. Pool. Min - idle = 0 # set the closing of the connection timeout spring. Redis. Lettuce. The shutdown - timeout = 100 msCopy the code

Custom RedisTemplate

RedisTemplate is the Redis operation class provided by Spring, through which we can do most of the Redis operations.

As long as we import redis dependencies and have redis connection information configured correctly, SpringBoot will give us a default RedisTemplate based on our configuration.

But there are two things about the RedisTemplate generated by default that don’t quite fit into your daily development habits

  1. Default generatedRedisTemplate<K, V>The receivedkeyandvalueFor generics, type conversion is often required, so direct use is not very convenient
  2. Is generated by default RedisTemplate serialization, use JdkSerializationRedisSerializer, storage to redis, content of binary bytes, unfavorable to view the original content

For the first problem, the general convention is to replace RedisTemplate

with RedisTemplate

, So for the second problem, you usually serialize the data to JSON and store it in Redis, and the other nice thing about serializing to JSON is that across languages, Other languages can also read what you store in Redis
,>
,>

To achieve the above two purposes, we need to customize our own RedisTemplate.

As follows, create a Config class to configure your custom RedisTemplate

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
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.*;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {
    
    @Bean
    RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        / / configuration json serializer - Jackson2JsonRedisSerializer
        Jackson2JsonRedisSerializer<Object> jacksonSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper objectMapper = new ObjectMapper()
                // Extend the serializer to add support for serialization and deserialization of time classes in java.time.* packages
                .registerModule(new ParameterNamesModule())
                .registerModule(new Jdk8Module())
                .registerModule(new JavaTimeModule());
        jacksonSerializer.setObjectMapper(objectMapper);

        / / create and configure a custom RedisTemplateRedisOperator
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // Serialize key to a string
        template.setKeySerializer(new StringRedisSerializer());
        // Serialize the hash key to a string
        template.setHashKeySerializer(new StringRedisSerializer());
        // Serialize value to JSON
        template.setValueSerializer(jacksonSerializer);
        // Serialize the hash value to JSON
        template.setHashValueSerializer(jacksonSerializer);
        // Set the connector
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForHash();
    }

    @Bean
    public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForValue();
    }

    @Bean
    public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForList();
    }

    @Bean
    public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForSet();
    }

    @Bean
    public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
        returnredisTemplate.opsForZSet(); }}Copy the code

Custom Redis action classes

Although RedisTemplate has encapsulated redis operations to a certain extent, it is still inconvenient to use it directly. In actual development, RedisTemplate is generally further encapsulated to form a simple and convenient REDis operation class.

Of course, you can choose not to wrap, depending on personal preference.

Refer to the custom Redis action class based on RedisTemplate for detailed encapsulation classes.

Spring Cache

Spring Cache is a Spring solution for caching scenarios. Use @cacheput, @cacheevict, and @cacheable annotations to store, query, and delete the cache

When spring-boot-starter-data-redis is introduced, using the @enablecaching annotation on the @Configuration class will “activate” the Spring Cache.

Spring Cache configures the default Cache manager and key generator for us, but the serialization of the Cache by the Cache manager and the keys generated by the key generator are not easy to read. Custom cache managers and key generators are recommended

If you don’t need Spring Cache, don’t bother.

Note: Spring Cache does not only use Redis as a Cache container, but other Cache middleware, such as MemCache, supports it.Copy the code

Configure Spring Cache

Type =redis # The expiration time of the cache added via the Spring cache annotation, in seconds (this is a custom attribute) cache.expireTime=60Copy the code

The most important thing is to specify the type of cache to use and a custom variable that the cache manager will use later

Configure the cache manager and key generator

import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializationContext; import org.springframework.data.redis.serializer.StringRedisSerializer; import java.lang.reflect.Method; import java.time.Duration; @configuration @enablecaching Public class CacheConfig extends CachingConfigurerSupport { @value ("${cache.expireTime}") private int cacheExpireTime; @cacheable; @cacheevict; Key generation policy * This configuration applies to all caches managed by the cache manager * The final generated key is the cache class annotation specified by cacheNames:: class name: method name # Parameter value 1, parameter value 2... * * @return */ @Bean public KeyGenerator keyGenerator() { return new KeyGenerator() { @Override public Object generate(Object target, Method method, Object... params) { StringBuffer sb = new StringBuffer(); sb.append(target.getClass().getName()); sb.append(":"); sb.append(method.getName()); sb.append("#"); for (Object obj : params) { sb.append(obj.toString()); sb.append(","); } return sb.substring(0, sb.length() - 1); }}; } /** * configure the CacheManager */ @bean public CacheManager CacheManager (RedisConnectionFactory factory) {// configure the json serializer - Jackson2JsonRedisSerializer Jackson2JsonRedisSerializer<Object> jacksonSerializer = new Jackson2JsonRedisSerializer<>(Object.class); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jacksonSerializer.setObjectMapper(objectMapper); // The key point is that the serialization used by Spring Cache annotations comes from this. Without this configuration, the JDK's own serialization is not affected. Just print it out is not suitable for the human eye to identify RedisCacheConfiguration cacheConfig = RedisCacheConfiguration. DefaultCacheConfig () / / key serialization into a string SerializeKeysWith (RedisSerializationContext. SerializationPair. FromSerializer (new StringRedisSerializer ())) / / value Serialize to JSON SerializeValuesWith (RedisSerializationContext. SerializationPair. FromSerializer (jacksonSerializer)) / / / / value serialization way Sets the cache expiration time, the unit seconds. EntryTtl (Duration. OfSeconds (cacheExpireTime)) / / no cache a null value. DisableCachingNullValues (); return RedisCacheManager.builder(factory) .cacheDefaults(cacheConfig) .build(); }}Copy the code

conclusion

Most of the tutorials on integrating Redis with Spring Boot on the Internet are about configuring Redis and Spring Cache together, which can be misleading.

Redis and Spring Cache are two different things, so I purposely split the above tutorial into two configuration files.

You can use Redis without Spring Cache, or vice versa.

So why are they often discussed together? The reason is that there is also a link

From the perspective of Reids, Spring Cache provides a convenient way to manipulate REids and provides an excellent solution for caching scenarios.

From a Spring cache perspective, REIDS provide a cache container that can be placed in REids.

The cache manager’s manipulation of REids is also implemented through the redisTemplate.