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
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