| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- package cn.hobbystocks.auc.common.config;
- import io.lettuce.core.ClientOptions;
- import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
- import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
- import org.springframework.cache.annotation.CachingConfigurerSupport;
- import org.springframework.cache.annotation.EnableCaching;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.data.redis.connection.RedisConnectionFactory;
- import org.springframework.data.redis.connection.RedisSentinelConfiguration;
- 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.core.script.DefaultRedisScript;
- import org.springframework.data.redis.serializer.StringRedisSerializer;
- import com.fasterxml.jackson.annotation.JsonAutoDetect;
- import com.fasterxml.jackson.annotation.JsonTypeInfo;
- import com.fasterxml.jackson.annotation.PropertyAccessor;
- import com.fasterxml.jackson.databind.ObjectMapper;
- import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
- /**
- * redis配置
- *
- * @author ruoyi
- */
- @Configuration
- @EnableCaching
- public class RedisConfig extends CachingConfigurerSupport {
- @Bean
- @ConditionalOnProperty(name = "hobbystocks.redis.sentinel.nodes")
- public LettuceConnectionFactory redisConnectionFactory(RedisProperties redisProperties, @Value("${hobbystocks.redis.sentinel.nodes:}") String hosts) {
- // 创建 Redis 哨兵配置
- RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration()
- .master(redisProperties.getSentinel().getMaster()); // 设置主节点名称,确保与哨兵配置一致
- for (String host : hosts.split(",")) {
- sentinelConfig.sentinel(host.split(":")[0], Integer.parseInt(host.split(":")[1]));
- }
- // 如果 Redis 服务器设置了密码,则可以在此配置
- sentinelConfig.setPassword(redisProperties.getPassword());
- sentinelConfig.setDatabase(redisProperties.getDatabase());
- // 配置连接池参数
- GenericObjectPoolConfig<Object> poolConfig = new GenericObjectPoolConfig<>();
- poolConfig.setMaxTotal(redisProperties.getLettuce().getPool().getMaxActive()); // 最大连接数
- poolConfig.setMaxIdle(redisProperties.getLettuce().getPool().getMaxIdle()); // 最大空闲连接数
- poolConfig.setMinIdle(redisProperties.getLettuce().getPool().getMinIdle()); // 最小空闲连接数
- // 配置客户端选项,启用自动重连
- ClientOptions clientOptions = ClientOptions.builder()
- .autoReconnect(true)
- .disconnectedBehavior(ClientOptions.DisconnectedBehavior.REJECT_COMMANDS)
- .build();
- // 创建 Lettuce 连接池配置
- LettucePoolingClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder()
- .poolConfig(poolConfig)
- .clientOptions(clientOptions)
- .clientOptions(ClientOptions.builder()
- .pingBeforeActivateConnection(true) // 在激活连接前发送 ping
- .build())
- .build();
- // 创建并配置 Lettuce 连接工厂
- return new LettuceConnectionFactory(sentinelConfig, clientConfig);
- }
- @Bean
- @SuppressWarnings(value = { "unchecked", "rawtypes" })
- public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
- RedisTemplate<Object, Object> template = new RedisTemplate<>();
- template.setConnectionFactory(connectionFactory);
- FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);
- ObjectMapper mapper = new ObjectMapper();
- mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
- mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
- serializer.setObjectMapper(mapper);
- // 使用StringRedisSerializer来序列化和反序列化redis的key值
- template.setKeySerializer(new StringRedisSerializer());
- template.setValueSerializer(serializer);
- // Hash的key也采用StringRedisSerializer的序列化方式
- template.setHashKeySerializer(new StringRedisSerializer());
- template.setHashValueSerializer(serializer);
- template.afterPropertiesSet();
- return template;
- }
- @Bean
- public DefaultRedisScript<Long> limitScript()
- {
- DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
- redisScript.setScriptText(limitScriptText());
- redisScript.setResultType(Long.class);
- return redisScript;
- }
- /**
- * 限流脚本
- */
- private String limitScriptText()
- {
- return "local key = KEYS[1]\n" +
- "local count = tonumber(ARGV[1])\n" +
- "local time = tonumber(ARGV[2])\n" +
- "local current = redis.call('get', key);\n" +
- "if current and tonumber(current) > count then\n" +
- " return tonumber(current);\n" +
- "end\n" +
- "current = redis.call('incr', key)\n" +
- "if tonumber(current) == 1 then\n" +
- " redis.call('expire', key, time)\n" +
- "end\n" +
- "return tonumber(current);";
- }
- }
|