Spring Boot Series: Integrating Redis Database Distributed Tools Redisson Cache Spring Cache

Integrated Redis database distributed tool Redisson cache Spring Cache

Redis client

Jedis

Jedis is a lightweight Redis client implemented in Java, with a simple and Socket-based operation mode and high performance.

Jedis API provides comprehensive support for Redis commands.

Using blocked I/O operations, method calls are all synchronous, and the program flow cannot be executed until the socket finishes processing I/O, and asynchronous operations are not supported.

It is directly connected to Redis Server, and it is not thread-safe in a multi-threaded environment, and Jedis needs to be operated through a connection pool.

? Lettuce

Lettuce Scalable thread-safe Redis client. Multiple threads can share the same RedisConnection, using the Netty NIO framework to efficiently manage multiple connections.

Supports synchronous, asynchronous, reactive programming, auto-reconnect, master-slave, cluster, sentinel, pipeline and encoder.

Starting with Spring Boot 2.x, Lettuce has replaced Jedis as the default Redis client for Spring Boot.

? Redisson

Redisson is a Java In-Memory Data Grid implemented on top of Redis. It not only provides a series of distributed common Java objects, but also provides many distributed services.

Redisson provides the easiest and most convenient way to use Redis.

Suitable for distributed applications, distributed caches, distributed session management, distributed services (tasks, delayed tasks, executors).

When there is no distributed scenario, lettuce is preferred for higher performance; distributed locks, distributed objects, distributed collections, etc. are needed, and lettuce + redisson can be used in combination.

?Spring Boot integrates Redis

?Dependency of Spring Data Redis

Maven introduces dependencies and directly uses the default version of Spring Boot (using the default Lettuce client)

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

Introduce commons-pool2 dependency as Lettuce’s connection pool

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

Configuration of Spring Data Redis

Add configuration, refer to org.springframework.boot.autoconfigure.data.redis.RedisProperties

## Redis database index (default is 0)
spring.redis.database=0
## Redis server address (default is localhost)
spring.redis.host=127.0.0.1
## Redis server connection port (6379 by default)
spring.redis.port=6379
## Redis server connection password (default is empty)
spring.redis.password=
## Connection timeout (milliseconds)
spring.redis.timeout=1000
## The maximum number of connections in the connection pool (the default is 8. Use a negative value to indicate no limit)
spring.redis.lettuce.pool.max-active=8
## The maximum blocking waiting time of the connection pool (the default is -1. Use a negative value to indicate no limit)
spring.redis.lettuce.pool.max-wait=-1
## Maximum idle connections in the connection pool (8 by default)
spring.redis.lettuce.pool.max-idle=8
## The minimum idle connection in the connection pool (default is 0)
spring.redis.lettuce.pool.min-idle=0

Use of Spring Data Redis

Spring Data Redis injects RedisTemplate redisTemplate and StringRedisTemplate stringRedisTemplate into the container by default. It is Spring’s encapsulation of Redis operations, through the encapsulated API. Operate Redis.

Reference org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration

Example of use

@Autowired
private StringRedisTemplate stringRedisTemplate;
@Autowired
private RedisTemplate<String, Object> redisTemplate;

@GetMapping("/stringRedis/add")
public String stringRedisAdd(String str) {<!-- -->
    stringRedisTemplate.opsForValue().set("stringRedis", str);
    return stringRedisTemplate.opsForValue().get("stringRedis");
}

@GetMapping("/redis/add")
public SysAccount redisAdd() {<!-- -->
    redisTemplate.opsForValue().set("redis", new SysAccount().setAccount("don"));
    return JSONUtil.toBean(stringRedisTemplate.opsForValue().get("redis"), SysAccount.class);
}
opsForValue --> string operation
opsForHash --> hash operation
opsForList --> list operation
opsForSet --> set operation
opsForZSet --> Zset operation

The test is complete, view the data of the Redis database

RedisTemplate uses JdkSerializationRedisSerializer serialization by default

Spring Data Redis custom serialization

Write Redis configuration class RedisConfig Customize RedisTemplate cache serialization configuration

@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {<!-- -->

    // create RedisTemplate object
    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
    // Set the RedisConnection factory (a factory that implements access to various Java Redis clients)
    redisTemplate.setConnectionFactory(redisConnectionFactory);

    // Replace default serialization with Jackson2JsonRedisSerialize
    Jackson2JsonRedisSerializer<?> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);

    ObjectMapper mapper = new ObjectMapper();
    mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    mapper.activateDefaultTyping(mapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);

    jackson2JsonRedisSerializer.setObjectMapper(mapper);

    redisTemplate.setDefaultSerializer(jackson2JsonRedisSerializer);

    redisTemplate.setKeySerializer(StringRedisSerializer.UTF_8);

    return redisTemplate;
}

Test, view data in Redis database, JSON format data

The StringRedisSerializer serialization mechanism used by StringRedisTemplate by default, simple string serialization, key and value are all String strings, no need to modify. Reference org.springframework.data.redis.core.StringRedisTemplate

The RedisSerializer interface is a Redis serialization interface for serialization of Redis KEY and VALUE

org.springframework.data.redis.serializer.RedisSerializer

public interface RedisSerializer<T> {<!-- -->
    @Nullable
    byte[] serialize(@Nullable T t) throws SerializationException;

    @Nullable
    T deserialize(@Nullable byte[] bytes) throws SerializationException;

    static RedisSerializer<Object> java() {<!-- -->
        return java((ClassLoader)null);
    }

    static RedisSerializer<Object> java(@Nullable ClassLoader classLoader) {<!-- -->
        return new JdkSerializationRedisSerializer(classLoader);
    }

    static RedisSerializer<Object> json() {<!-- -->
        return new GenericJackson2JsonRedisSerializer();
    }

    static RedisSerializer<String> string() {<!-- -->
        return StringRedisSerializer.UTF_8;
    }

    static RedisSerializer<byte[]> byteArray() {<!-- -->
        return ByteArrayRedisSerializer.INSTANCE;
    }

    default boolean canSerialize(Class<?> type) {<!-- -->
        return ClassUtils.isAssignable(this.getTargetType(), type);
    }

    default Class<?> getTargetType() {<!-- -->
        return Object. class;
    }
}

The implementation classes are:

JdkSerializationRedisSerializer: Serialize objects. Objects must implement the Serializable interface. The serialized content has other content besides the attribute content. The length is long and difficult to read. This serialization method is adopted by default.

Jackson2JsonRedisSerializer: The serialized object is a JSON string. The serialized object does not need to implement the Serializable interface. After serialization, the result is easy to read, stores fewer bytes, and is faster.

Spring Boot integrates Redisson

Redisson dependencies

Maven introduces dependencies, and the version is selected according to the Spring Boot version

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>${redisson.version}</version>
</dependency>

Reference https://github.com/redisson/redisson/tree/master/redisson-spring-boot-starter

Redisson configuration

Add configuration file redisson-config.yml

singleServerConfig:
  address: "redis://127.0.0.1:6379"
  password: null
  clientName: null
  database: 0
  idleConnectionTimeout: 10000
  pingTimeout: 1000
  connectTimeout: 10000
  timeout: 3000
  retryAttempts: 3
  retryInterval: 1500
  reconnectionTimeout: 3000
  failedAttempts: 3
  subscriptionsPerConnection: 5
  subscriptionConnectionMinimumIdleSize: 1
  subscriptionConnectionPoolSize: 50
  connectionMinimumIdleSize: 32
  connectionPoolSize: 64
  dnsMonitoringInterval: 5000
threads: 0
nettyThreads: 0
codec:
  class: "org.redisson.codec.JsonJacksonCodec"
transportMode: "NIO"

Configure in application.yml

spring:
  redis:
    redisson:
      config: classpath:redisson-config.yml

After configuration, you can use RedissonClient to operate Redis

For details, please refer to org.redisson.spring.starter.RedissonAutoConfiguration

Use of RedissonClient

@Autowired
private RedissonClient redissonClient;

@GetMapping("/set/{key}")
public String set(@PathVariable String key) {<!-- -->
    RBucket<String> keyObj = redissonClient.getBucket(key);
    keyObj.set(key + new Random().nextInt(1000));
    return key;
}

@GetMapping("/get/{key}")
public String get(@PathVariable String key) {<!-- -->
    RBucket<String> keyObj = redissonClient.getBucket(key);
    return keyObj. get();
}

lock use

@GetMapping("/lock")
public void redissonLock() {<!-- -->
    RLock lock = redissonClient.getLock("lock");
    try {<!-- -->
        // 1. Acquire redis lock
        if (lock. tryLock(3, TimeUnit. SECONDS)) {<!-- -->
            try {<!-- -->
                // 2. Get inventory
                RBucket<Integer> keyObj = redissonClient.getBucket("xiaomi");
                Integer stock = keyObj. get();
                if (stock != null) {<!-- -->
                    // 3. Compare and deduct inventory
                    if (stock > 0) {<!-- -->
                        // 4. Set inventory
                        keyObj.set(--stock);
                        TimeUnit. SECONDS. sleep(1);
                        System.out.println("Purchased successfully");
                    }
                }
            } finally {<!-- -->
                lock. unlock();
            }
        }
    } catch (InterruptedException e) {<!-- -->
        e.printStackTrace();
    }
}

More lock usage reference https://github.com/redisson/redisson/wiki/8.-distributed-locks-and-synchronizers

Configure using RedissonAutoConfigurationCustomizer

Create a new Redisson configuration item class

@Data
@ConfigurationProperties(prefix = "redisson")
public class RedissonProperties {<!-- -->
    /**
     * Redis cache key prefix
     */
    private String keyPrefix;
    /**
     * Number of thread pools, default value = number of current processing cores * 2
     */
    private int threads;
    /**
     * Number of Netty thread pools, default value = current number of processing cores * 2
     */
    private int nettyThreads;
    /**
     * transfer mode
     */
    private TransportMode transportMode;
    /**
     * Stand-alone service configuration
     */
    private SingleServerConfig singleServerConfig;
    /**
     * Cluster service configuration
     */
    private ClusterServersConfig clusterServersConfig;

    @Data
    @NoArgsConstructor
    public static class SingleServerConfig {<!-- -->
        /**
         * client name
         */
        private String clientName;
        /**
         * Minimum number of idle connections
         */
        private int connectionMinimumIdleSize;
        /**
         * Connection pool size
         */
        private int connectionPoolSize;
        /**
         * Connection idle timeout, unit: milliseconds
         */
        private int idleConnectionTimeout;
        /**
         * Command wait timeout, unit: milliseconds
         */
        private int timeout;
        /**
         * Command failure retries
         */
        private int retryAttempts;
        /**
         * Command failure retries
         */
        private int retryInterval;
        /**
         * The minimum number of idle connections for publish and subscribe connections
         */
        private int subscriptionConnectionMinimumIdleSize;
        /**
         * Publish and subscribe connection pool size
         */
        private int subscriptionConnectionPoolSize;
        /**
         * The maximum number of subscriptions for a single connection
         */
        private int subscriptionsPerConnection;
        /**
         * DNS monitoring interval, unit: millisecond
         */
        private int dnsMonitoringInterval;
    }

    @Data
    @NoArgsConstructor
    public static class ClusterServersConfig {<!-- -->
        /**
         * client name
         */
        private String clientName;
        /**
         * master minimum number of idle connections
         */
        private int masterConnectionMinimumIdleSize;
        /**
         * master connection pool size
         */
        private int masterConnectionPoolSize;
        /**
         * slave minimum number of idle connections
         */
        private int slaveConnectionMinimumIdleSize;
        /**
         * slave connection pool size
         */
        private int slaveConnectionPoolSize;
        /**
         * Connection idle timeout, unit: milliseconds
         */
        private int idleConnectionTimeout;
        /**
         * Command wait timeout, unit: milliseconds
         */
        private int timeout;
        /**
         * Command failure retries
         */
        private int retryAttempts;
        /**
         * Command failure retries
         */
        private int retryInterval;
        /**
         * Failed slave node reconnection interval
         */
        private int failedSlaveReconnectionInterval;
        /**
         * Failed slave node verification interval time
         */
        private int failedSlaveCheckInterval;
        /**
         * The maximum number of subscriptions for a single connection
         */
        private int subscriptionsPerConnection;
        /**
         * The minimum number of idle connections for publish and subscribe connections
         */
        private int subscriptionConnectionMinimumIdleSize;
        /**
         * Publish and subscribe connection pool size
         */
        private int subscriptionConnectionPoolSize;
        /**
         * read mode
         */
        private ReadMode readMode;
        /**
         * Subscription mode
         */
        private SubscriptionMode subscriptionMode;
    }
}

Add yml to configure Redisson

--- ##### redis configuration #####
spring:
  redis:
    host: 127.0.0.1
    port: 6379
    database: 0
# password:
    timeout: 5000
    # Whether to enable ssl
    ssl: false
    lettuce:
      pool:
        # The maximum idle connection in the connection pool defaults to 8
        max-idle: 8
        # The minimum idle connection in the connection pool defaults to 0
        min-idle: 0
        # The maximum number of connections in the connection pool is 8 by default, and a negative number means there is no limit
        max-active: 8
        # The maximum blocking waiting time of the connection pool (use a negative value to indicate no limit) default -1
        max-wait: -1
--- # redisson client configuration
redisson:
  key-prefix: ${<!-- -->spring.application.name}
  # Number of thread pools
  threads: 16
  # Number of Netty thread pools
  netty-threads: 32
  # transfer mode
  transport-mode: "NIO"
  # Single node configuration
  single-server-config:
    # client name
    client-name: ${<!-- -->spring.application.name}
    # Minimum number of idle connections
    connection-minimum-idle-size: 32
    # Connection pool size
    connection-pool-size: 64
    # Connection idle timeout, unit: milliseconds
    idle-connection-timeout: 10000
    # command wait timeout, unit: milliseconds
    timeout: 3000
    # If the attempt to send within this limit is successful, start enabling timeout timing.
    retry-attempts: 3
    # Command retry sending interval, unit: milliseconds
    retry-interval: 1500
    # The minimum number of idle connections for publish and subscribe connections
    subscription-connection-minimum-idle-size: 1
    # publish and subscribe connection pool size
    subscription-connection-pool-size: 50
    # The maximum number of subscriptions for a single connection
    subscriptions-per-connection: 5
    # dns monitoring interval, unit: milliseconds
    dns-monitoring-interval: 5000

Configure Redisson

@EnableConfigurationProperties(RedissonProperties.class)
@Configuration
public class DonRedissonAutoConfiguration {<!-- -->

    @Bean
    public RedissonAutoConfigurationCustomizer redissonCustomizer(RedissonProperties redissonProperties) {<!-- -->

        log.info("DonRedissonAutoConfiguration redissonCustomizer init ...");

        return config -> {<!-- -->
            config.setThreads(redissonProperties.getThreads())
                    .setNettyThreads(redissonProperties.getNettyThreads())
                    .setCodec(JsonJacksonCodec.INSTANCE)
                    .setTransportMode(redissonProperties.getTransportMode());

            RedissonProperties.SingleServerConfig singleServerConfig = redissonProperties.getSingleServerConfig();
            RedissonProperties.ClusterServersConfig clusterServersConfig = redissonProperties.getClusterServersConfig();

            // stand-alone mode
            if (Objects. nonNull(singleServerConfig)) {<!-- -->
                config. useSingleServer()
                        .setClientName(singleServerConfig.getClientName())
                        // Set the Redis key prefix
                        .setNameMapper(new KeyPrefixHandler(redissonProperties.getKeyPrefix()))
                        .setConnectTimeout(singleServerConfig.getTimeout())
                        .setTimeout(singleServerConfig.getTimeout())
                        .setRetryAttempts(singleServerConfig.getRetryAttempts())
                        .setRetryInterval(singleServerConfig.getRetryInterval())
                        .setSubscriptionConnectionMinimumIdleSize(singleServerConfig.getSubscriptionConnectionMinimumIdleSize())
                        .setSubscriptionConnectionPoolSize(singleServerConfig.getSubscriptionConnectionPoolSize())
                        .setSubscriptionsPerConnection(singleServerConfig.getSubscriptionsPerConnection())
                        .setConnectionMinimumIdleSize(singleServerConfig.getConnectionMinimumIdleSize())
                        .setConnectionPoolSize(singleServerConfig.getConnectionPoolSize())
                        .setIdleConnectionTimeout(singleServerConfig.getIdleConnectionTimeout())
                        .setDnsMonitoringInterval(singleServerConfig.getDnsMonitoringInterval());
            }

            // cluster mode
            if (Objects.nonNull(clusterServersConfig)) {<!-- -->
                config. useClusterServers()
                        .setClientName(clusterServersConfig.getClientName())
                        // Set the Redis key prefix
                        .setNameMapper(new KeyPrefixHandler(redissonProperties.getKeyPrefix()))
                        .setConnectTimeout(clusterServersConfig.getTimeout())
                        .setTimeout(clusterServersConfig.getTimeout())
                        .setMasterConnectionMinimumIdleSize(clusterServersConfig.getMasterConnectionMinimumIdleSize())
                        .setMasterConnectionPoolSize(clusterServersConfig.getMasterConnectionPoolSize())
                        .setSlaveConnectionMinimumIdleSize(clusterServersConfig.getSlaveConnectionMinimumIdleSize())
                        .setSlaveConnectionPoolSize(clusterServersConfig.getSlaveConnectionPoolSize())
                        .setIdleConnectionTimeout(clusterServersConfig.getIdleConnectionTimeout())
                        .setRetryAttempts(clusterServersConfig.getRetryAttempts())
                        .setRetryInterval(clusterServersConfig.getRetryInterval())
                        .setFailedSlaveReconnectionInterval(clusterServersConfig.getFailedSlaveReconnectionInterval())
                        .setFailedSlaveCheckInterval(clusterServersConfig.getFailedSlaveCheckInterval())
                        .setSubscriptionsPerConnection(clusterServersConfig.getSubscriptionsPerConnection())
                        .setSubscriptionConnectionMinimumIdleSize(clusterServersConfig.getSubscriptionConnectionMinimumIdleSize())
                        .setSubscriptionConnectionPoolSize(clusterServersConfig.getSubscriptionConnectionPoolSize())
                        .setReadMode(clusterServersConfig.getReadMode())
                        .setSubscriptionMode(clusterServersConfig.getSubscriptionMode());
            }
        };
    }

}

Test distributed lock

@GetMapping("/lock")
public void lock() {<!-- -->
    RLock lock = redissonClient.getLock("lock");
    try {<!-- -->
        if (lock. tryLock(3, TimeUnit. SECONDS)) {<!-- -->
            try {<!-- -->
                TimeUnit. SECONDS. sleep(1);
                log.info("Current thread name: {}", Thread.currentThread().getName());
            } finally {<!-- -->
                lock. unlock();
            }
        }
    } catch (InterruptedException e) {<!-- -->
        e.printStackTrace();
    }
}

Cluster configuration

--- ##### redis configuration #####
spring:
  redis:
    cluster:
      nodes:
        - 127.0.0.1:6380
        - 127.0.0.1:6381
        - 127.0.0.1:6382
        - 127.0.0.1:6383
        - 127.0.0.1:6384
        - 127.0.0.1:6385
    database: 0
    # Connection timeout
    timeout: 5000
    # Whether to enable ssl
    ssl: false
    lettuce:
      pool:
        # The maximum idle connection in the connection pool defaults to 8
        max-idle: 8
        # The minimum idle connection in the connection pool defaults to 0
        min-idle: 0
        # The maximum number of connections in the connection pool is 8 by default, and a negative number means there is no limit
        max-active: 8
        # The maximum blocking waiting time of the connection pool (use a negative value to indicate no limit) default -1
        max-wait: -1
--- # redisson client configuration
redisson:
  key-prefix: ${<!-- -->spring.application.name}
  # Number of thread pools
  threads: 16
  # Number of Netty thread pools
  netty-threads: 32
  # transfer mode
  transport-mode: "NIO"
  cluster-servers-config:
    # client name
    client-name: ${<!-- -->spring.application.name}
    # The minimum number of idle connections for the primary node
    master-connection-minimum-idle-size: 24
    # master node connection pool size
    master-connection-pool-size: 64
    # The minimum number of idle connections from the node
    slave-connection-minimum-idle-size: 24
    # Slave node connection pool size
    slave-connection-pool-size: 64
    # Connection idle timeout, unit: milliseconds
    idle-connection-timeout: 10000
    # command wait timeout, unit: milliseconds
    timeout: 3000
    # Command failure retries
    retry-attempts: 3
    # Command retry sending interval, unit: milliseconds
    retry-interval: 1500
    # Failed slave node reconnection interval time
    failed-slave-reconnection-interval: 3000
    # Failed slave node verification interval time
    failed-slave-check-interval: 60000
    # The maximum number of subscriptions for a single connection
    subscriptions-per-connection: 5
    # The minimum number of idle connections for publish and subscribe connections
    subscription-connection-minimum-idle-size: 1
    # publish and subscribe connection pool size
    subscription-connection-pool-size: 50
    # read mode
    read-mode: "slave"
    # Subscription mode
    subscription-mode: "master"

For more API operations, refer to Redisson official website https://github.com/redisson/redisson

Redis cache based on Spring Cache

Spring Cache dependencies

Maven introduces dependencies

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

Spring Cache configuration

Add configuration in yml file

--- ##### spring cache configuration #####
spring:
  cache:
    type: redis
    cache-names: don

Enable support in the main startup class

@EnableCaching

After the configuration is complete, Spring Boot will automatically configure a RedisCacheManager class

Reference org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration

Spring Cache cache usage

Annotation @Cacheable caching value

Added to the query method, the return value of the method is cached. By default, the cached key is the parameter of the method, and the cached value is the return value of the method. The key can be specified manually, using the SpEL expression.

@GetMapping("/cache/get")
@Cacheable(key = "#str")
public String get(String str) {<!-- -->
    log.info("key {}", str);
    return LocalDateTime.now().toString();
}

Request method, query whether there is a value in the cache, if there is, return directly, if not, execute the method and put the value into the cache.

Annotation @CachePut Update cache value

The annotation is added to the update method, which can automatically update the return value of the method to the existing key.

@CachePut(key = "#str")
@GetMapping("/cache/put")
public String put(String str) {<!-- -->
    log.info("key {}", str);
    return LocalDateTime.now().toString();
}

Annotation @CacheEvict Delete cached value

Adding the annotation to the delete method will delete the value in the cache.

@CacheEvict(key = "#str")
@GetMapping("/cache/clear")
public String clear(String str) {<!-- -->
    log.info("key {}", str);
    return LocalDateTime.now().toString();
}

More using https://docs.spring.io/spring-framework/docs/5.3.27/reference/html/integration.html#cache-annotations

Custom configuration RedisCacheManager

RedisCacheManager can be manually configured to specify the serialization mechanism, cache duration, etc.

example

@Bean
public CacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory, CacheProperties cacheProperties) {<!-- -->

    log.info("DonCacheAutoConfiguration redisCacheManager init ...");

    Jackson2JsonRedisSerializer<?> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
    RedisSerializer<String> stringRedisSerializer = new StringRedisSerializer();

    ObjectMapper mapper = new ObjectMapper();
    mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    mapper.activateDefaultTyping(mapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);

    jackson2JsonRedisSerializer.setObjectMapper(mapper);

    // Configure serialization, the default expiration time is 10 minutes
    Duration timeToLive = cacheProperties.getRedis().getTimeToLive();
    RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
        .entryTtl(Objects.isNull(timeToLive) ? Duration.ofMinutes(10) : timeToLive)
        .computePrefixWith(name -> name + "::")
        .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(stringRedisSerializer))
        .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
        .disableCachingNullValues();

    return RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(config).transactionAware().build();
}

End…

https://github.com/redisson/redisson

https://spring.io/projects/spring-boot