1. 程式人生 > >SpringBoot整合Redis Lettuce

SpringBoot整合Redis Lettuce

最近在準備整合的基礎框架使用Spring Boot2搭建,其中Redis的支援不僅僅是豐富了它的API,更是替換掉底層Jedis的依賴,取而代之換成了Lettuce(生菜)

jedis跟lettuce的區別

  • Lettuce 和 Jedis 的定位都是Redis的client,所以他們當然都可以直接連線redis server。
  • Jedis在實現上是直接連線的redis server,如果在多執行緒環境下是非執行緒安全的,這個時候只有使用連線池,為每個Jedis例項增加物理連線
  • Lettuce的連線是基於Netty的,連線例項(StatefulRedisConnection)可以在多個執行緒間併發訪問,應為StatefulRedisConnection是執行緒安全的,所以一個連線例項(StatefulRedisConnection)就可以滿足多執行緒環境下的併發訪問,當然這個也是可伸縮的設計,一個連線例項不夠的情況也可以按需增加連線例項。

匯入依賴

在 pom.xml 中spring-boot-starter-data-redis的依賴,Spring Boot2.x 後底層不在是Jedis如果做版本升級的朋友需要注意下,第二個commons-pool2依賴不能少(連線池使用)。

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

配置檔案

由於Spring Boot2.x 的改動,連線池相關配置需要通過spring.redis.lettuce.pool 進行配置了

spring:
    redis:
        # Redis開關/預設關閉
        enabled: true
        database: 0
        password:     #redis密碼
        host: 127.0.0.1
        port: 6379
        lettuce:
            pool:
                max-active:  100 # 連線池最大連線數(使用負值表示沒有限制)
                max-idle: 100 # 連線池中的最大空閒連線
                min-idle: 50 # 連線池中的最小空閒連線
                max-wait: 6000 # 連線池最大阻塞等待時間(使用負值表示沒有限制)
        timeout: 1000

具體配置類

RedisConfig

@Configuration
@EnableCaching // 開啟快取支援
public class RedisConfig extends CachingConfigurerSupport {

   @Resource
   private LettuceConnectionFactory lettuceConnectionFactory;

   // 快取管理器
   @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {

        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))//key序列化方式
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer()))//value序列化方式
                .disableCachingNullValues()
                .entryTtl(Duration.ofSeconds(30*60));//快取過期時間


        RedisCacheManager.RedisCacheManagerBuilder builder = RedisCacheManager.RedisCacheManagerBuilder
                .fromConnectionFactory(lettuceConnectionFactory)
                .cacheDefaults(config)
                .transactionAware()
                .withInitialCacheConfigurations(getRedisCacheConfigurationMap());

        return builder.build();
    }
   
      private RedisSerializer<String> keySerializer() {
           return new StringRedisSerializer();
       }

       private RedisSerializer<Object> valueSerializer() {
          Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
           ObjectMapper om = new ObjectMapper();
           om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
           om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
           
           om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
           
           jackson2JsonRedisSerializer.setObjectMapper(om);
           return jackson2JsonRedisSerializer;
          
          
           // 設定序列化 兩種方式區別不大
//        return new GenericJackson2JsonRedisSerializer();
       }
   
   
    private Map<String, RedisCacheConfiguration> getRedisCacheConfigurationMap() {
        Map<String, RedisCacheConfiguration> redisCacheConfigurationMap = new HashMap<>();
        /**
         * @CacheConfig(cacheNames = "SsoCache")
         public class SsoCache{
            @Cacheable(keyGenerator = "cacheKeyGenerator")
            public String getTokenByGsid(String gsid) 
         }
         //二者選其一,可以使用value上的資訊,來替換類上cacheNames的資訊
         @Cacheable(value = "BasicDataCache",keyGenerator = "cacheKeyGenerator")
         public String getTokenByGsid(String gsid) 
         */
        //SsoCache和BasicDataCache進行過期時間配置
        redisCacheConfigurationMap.put("menuCache", this.getRedisCacheConfigurationWithTtl(24*60*60));
        redisCacheConfigurationMap.put("BasicDataCache", this.getRedisCacheConfigurationWithTtl(30*60));
        return redisCacheConfigurationMap;
    }

    private RedisCacheConfiguration getRedisCacheConfigurationWithTtl(Integer seconds) {

        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
        redisCacheConfiguration = redisCacheConfiguration.entryTtl(Duration.ofSeconds(seconds))
              .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))//key序列化方式
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer()))//value序列化方式;
                ;
        return redisCacheConfiguration;
    }
   
    @Bean(name = "cacheKeyGenerator")
    public KeyGenerator cacheKeyGenerator() {
        return new KeyGenerator() {
            @Override
            public Object generate(Object target, Method method, Object... params) {
               
               StringBuffer sb = new StringBuffer();
                sb.append(target.getClass().getName());
                sb.append(method.getName());
                for (Object obj : params) {
                    sb.append(obj.toString());
                }
                return sb.toString();
            }
        };
    }

   /**
    * RedisTemplate配置
    */
   @Bean
   public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
      // 設定序列化
//    
      RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
      redisTemplate.setKeySerializer(keySerializer());
        redisTemplate.setHashKeySerializer(keySerializer());
//        redisTemplate.setHashValueSerializer(valueSerializer());
//        redisTemplate.setValueSerializer(valueSerializer());
        redisTemplate.setConnectionFactory(lettuceConnectionFactory);
      return redisTemplate;
   }
}

RedisCacheManager

public class RedisCacheManager implements CacheManager {
    /**
     * 用於shiro中用到的cache
     */
    private ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<>();

    /**
     * redis cache 工具類
     */
    private RedisTemplate redisTemplate = SpringUtils.getBean("redisTemplate");
//    @Autowired
//    private RedisTemplate redisTemplate;

    @Override
    public <K, V> Cache<K, V> getCache(String name) throws CacheException {
        Cache<K, V> cache = caches.get(name);
        if (cache == null) {
            synchronized (this) {
                cache = new RedisCache<>(3600, redisTemplate);
                caches.put(name, cache);
            }
        }
        return cache;
    }

}