RedisConfig.java 9.27 KB
package com.huaheng.framework.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.huaheng.framework.redis.serializer.SerializeUtils;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
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.context.annotation.Scope;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.lang.reflect.Method;
import java.time.Duration;

@Configuration
@EnableCaching // 开启缓存支持
public class RedisConfig extends CachingConfigurerSupport
{
    @Value("${redis.database}")
    private int database;

    @Value("${redis.host}")
    private String host;

    @Value("${redis.port}")
    private int port;

    @Value("${redis.password}")
    private String password;

    @Value("${redis.ssl}")
    private Boolean ssl;

    @Value("${redis.lettuce.pool.max-idle}")
    private int maxIdle;

    @Value("${redis.lettuce.pool.min-idle}")
    private int minIdle;

    @Value("${redis.lettuce.pool.max-total}")
    private int maxTotal;

    @Value("${redis.lettuce.pool.max-waitMillis}")
    private long maxWaitMillis;

    @Value("${redis.timeout}")
    private long timeout;

    private Duration timeToLive = Duration.ofSeconds(600);

    /**
     * 在没有指定缓存Key的情况下,key生成策略
     */
    @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(method.getName());
                for (Object obj : params)
                {
                    sb.append(obj.toString());
                }
                return sb.toString();
            }
        };
    }

    // 缓存管理器 使用Lettuce,和jedis有很大不同LettuceConnectionFactory lettuceConnectionFactory
    @Bean
    public CacheManager cacheManager()
    {
        // 关键点,spring cache的注解使用的序列化都从这来,没有这个配置的话使用的jdk自己的序列化,实际上不影响使用,只是打印出来不适合人眼识别
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))// key序列化方式
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(getValueSerializer()))// value序列化方式
                .disableCachingNullValues().entryTtl(timeToLive).disableCachingNullValues();
        ;// 缓存过期时间

        RedisCacheManager.RedisCacheManagerBuilder builder = RedisCacheManager.RedisCacheManagerBuilder
                .fromConnectionFactory(lettuceConnectionFactory())// 默认有锁 等待锁时间为0
                .cacheDefaults(redisCacheConfiguration).transactionAware();
        return builder.build();
    }

    /**
     * RedisTemplate配置 使用自定义redisTemplate的时候 重新定义序列化方式 LettuceConnectionFactory lettuceConnectionFactory
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate()
    {
        // 配置redisTemplate
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
        redisTemplate.setConnectionFactory(lettuceConnectionFactory());

        RedisSerializer<?> stringSerializer = new StringRedisSerializer();

        redisTemplate.setKeySerializer(stringSerializer);// key序列化
        redisTemplate.setValueSerializer(getValueSerializer());// value序列化new LZ4Serializer(getValueSerializer())
        redisTemplate.setHashKeySerializer(stringSerializer);// Hash key序列化
        redisTemplate.setHashValueSerializer(getValueSerializer());// Hash value序列化
        redisTemplate.afterPropertiesSet();

        return redisTemplate;
    }

    /**
     * shiroRedisTemplate配置 使用自定义shiroRedisTemplate的时候 重新定义序列化方式 LettuceConnectionFactory lettuceConnectionFactory
     */
    @Bean
    public RedisTemplate<String, Object> shiroRedisTemplate()
    {
        // 配置redisTemplate
        RedisTemplate<String, Object> shiroRedisTemplate = new RedisTemplate<String, Object>();
        shiroRedisTemplate.setConnectionFactory(lettuceConnectionFactory());

        RedisSerializer<?> stringSerializer = new StringRedisSerializer();

        shiroRedisTemplate.setKeySerializer(stringSerializer);// key序列化
        shiroRedisTemplate.setValueSerializer(new SerializeUtils<Object>());// value序列化
        shiroRedisTemplate.setHashKeySerializer(stringSerializer);// Hash key序列化
        shiroRedisTemplate.setHashValueSerializer(new SerializeUtils<Object>());// Hash value序列化
        shiroRedisTemplate.afterPropertiesSet();

        return shiroRedisTemplate;
    }

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

    private RedisSerializer<Object> getValueSerializer()
    {
        // 设置序列化
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(
                Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        return jackson2JsonRedisSerializer;
    }

    // 单机版配置连接参数
    @Bean
    public RedisStandaloneConfiguration redisStandaloneConfiguration()
    {
        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setDatabase(database);
        redisStandaloneConfiguration.setHostName(host);
        redisStandaloneConfiguration.setPort(port);
        redisStandaloneConfiguration.setPassword(RedisPassword.of(password));

        // 集群版配置
        // RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
        // String[] serverArray = clusterNodes.split(",");
        // Set<RedisNode> nodes = new HashSet<RedisNode>();
        // for (String ipPort : serverArray) {
        // String[] ipAndPort = ipPort.split(":");
        // nodes.add(new RedisNode(ipAndPort[0].trim(), Integer.valueOf(ipAndPort[1])));
        // }
        // redisClusterConfiguration.setPassword(RedisPassword.of(password));
        // redisClusterConfiguration.setClusterNodes(nodes);
        // redisClusterConfiguration.setMaxRedirects(maxRedirects);

        return redisStandaloneConfiguration;
    }

    /**
     * 配置LettuceClientConfiguration 包括线程池配置和安全项配置 genericObjectPoolConfig common-pool2线程池GenericObjectPoolConfig
     * genericObjectPoolConfig
     * 
     * @return lettuceClientConfiguration
     */
    @Bean
    public LettuceClientConfiguration lettuceClientConfiguration()
    {
        LettuceClientConfiguration lettuceClientConfiguration = LettucePoolingClientConfiguration.builder()
                .commandTimeout(Duration.ofMillis(timeout)).shutdownTimeout(Duration.ofMillis(200))
                .poolConfig(genericObjectPoolConfig()).build();
        if (ssl)
        {
            lettuceClientConfiguration.isUseSsl();
        }
        return lettuceClientConfiguration;
    }

    // 设置连接工厂
    @Bean
    public LettuceConnectionFactory lettuceConnectionFactory()
    {
        return new LettuceConnectionFactory(redisStandaloneConfiguration(), lettuceClientConfiguration());
    }

    /**
     * GenericObjectPoolConfig 连接池配置
     */
    @Bean
    @ConfigurationProperties(prefix = "redis.lettuce.pool")
    @Scope(value = "prototype")
    @SuppressWarnings("rawtypes")
    public GenericObjectPoolConfig genericObjectPoolConfig()
    {
        return new GenericObjectPoolConfig();
    }
}