SpringBoot集成Redis | 使用注解动态切换Redis库
【摘要】 SpringBoot集成Redis | 使用注解动态切换Redis库由于工作中不同的数据信息缓存在不同的redis的16个库中,当某个地方需要用到的时候,切换redis库不方便,下面讲解的即可简便操作,可直接集成于common包中本人已将项目打包到github,有需要的可以直接去拿项目地址-github:https://github.com/Linsider/redis大家看完可以导入项目跑...
SpringBoot集成Redis | 使用注解动态切换Redis库
由于工作中不同的数据信息缓存在不同的redis的16个库中,当某个地方需要用到的时候,切换redis库不方便,下面讲解的即可简便操作,可直接集成于common包中
本人已将项目打包到github,有需要的可以直接去拿
项目地址-github:https://github.com/Linsider/redis
大家看完可以导入项目跑一跑,有疑问可以在评论区留言,看到即回复
一、目录结构
二、创建redis切换库所需注解、类
2.1 application.yml配置
# Tomcat server: tomcat: uri-encoding: UTF-8 max-threads: 1000 min-spare-threads: 30 port: 8088 servlet: context-path: /redis-demo # mysql spring: http: multipart: max-file-size: 100MB max-request-size: 100MB enabled: true redis: database: 0 host: localhost port: 6379 password: # 密码(默认为空) timeout: 6000ms # 连接超时时长(毫秒) jedis: pool: max-active: 1000 # 连接池最大连接数(使用负值表示没有限制) max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制) max-idle: 10 # 连接池中的最大空闲连接 min-idle: 5 # 连接池中的最小空闲连接 cache: type: none huangtuL: redis: open: false # 是否开启redis缓存 true开启 false关闭 logging: level: debug level.com.example: debug path: logs/ file: huangtuL.log
2.2 创建自定义注解 RedisSelect
import java.lang.annotation.*; /** * author huangtuL */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface RedisSelect { /** * redis库 * @return */ int value() default 0; }
2.3 Redis配置类 RedisConfig (下面的注解即可直接回去yml中的redis配置)
import com.example.redis.SelectableRedisTemplate; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; import org.springframework.boot.autoconfigure.data.redis.RedisProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.data.redis.connection.RedisPassword; import org.springframework.data.redis.connection.RedisStandaloneConfiguration; import org.springframework.data.redis.connection.jedis.JedisClientConfiguration; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import redis.clients.jedis.JedisPoolConfig; import java.time.Duration; /** * Redis配置相关 * author huangtuL */ @Configuration @AutoConfigureAfter(RedisAutoConfiguration.class)// 自动获取application.yml中的配置 @EnableConfigurationProperties(RedisProperties.class) public class RedisConfig { private RedisProperties properties; public RedisConfig(RedisProperties properties){ this.properties = properties; } @Bean @Primary public JedisConnectionFactory jedisConnectionFactory(){ RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(); config.setHostName(properties.getHost()); config.setPort(properties.getPort()); config.setPassword(RedisPassword.of(properties.getPassword())); config.setDatabase(properties.getDatabase()); return new JedisConnectionFactory(config, getJedisClientConfiguration()); } private JedisClientConfiguration getJedisClientConfiguration() { JedisClientConfiguration.JedisClientConfigurationBuilder builder = JedisClientConfiguration.builder(); if (properties.isSsl()) { builder.useSsl(); } if (properties.getTimeout() != null) { Duration timeout = properties.getTimeout(); builder.readTimeout(timeout).connectTimeout(timeout); } RedisProperties.Pool pool = properties.getJedis().getPool(); if (pool != null) { builder.usePooling().poolConfig(jedisPoolConfig(pool)); } return builder.build(); } private JedisPoolConfig jedisPoolConfig(RedisProperties.Pool pool) { JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(pool.getMaxActive()); config.setMaxIdle(pool.getMaxIdle()); config.setMinIdle(pool.getMinIdle()); if (pool.getMaxWait() != null) { config.setMaxWaitMillis(pool.getMaxWait().toMillis()); } return config; } @Bean(name = "redisTemplate") @Primary public SelectableRedisTemplate redisTemplate() { SelectableRedisTemplate redisTemplate = new SelectableRedisTemplate(); redisTemplate.setConnectionFactory(jedisConnectionFactory()); return redisTemplate; } }
2.4 redis工具类 RedisUtils(这没啥说的)
import com.alibaba.fastjson.JSON; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import java.util.concurrent.TimeUnit; /** * Redis工具类 * * author huangtuL */ @Component public class RedisUtils { @Autowired private StringRedisTemplate redisTemplate; private ValueOperations<String, String> valueOperations; @PostConstruct public void init(){ this.valueOperations = redisTemplate.opsForValue(); } /** 默认过期时长,单位:秒 */ public final static long DEFAULT_EXPIRE = 60 * 60 * 24; /** 不设置过期时长 */ public final static long NOT_EXPIRE = -1; public void set(String key, Object value, long expire){ valueOperations.set(key, toJson(value)); if(expire != NOT_EXPIRE){ redisTemplate.expire(key, expire, TimeUnit.SECONDS); } } public void set(String key, Object value){ set(key, value, DEFAULT_EXPIRE); } public <T> T get(String key, Class<T> clazz, long expire) { String value = valueOperations.get(key); if(expire != NOT_EXPIRE){ redisTemplate.expire(key, expire, TimeUnit.SECONDS); } return value == null ? null : fromJson(value, clazz); } public <T> T get(String key, Class<T> clazz) { return get(key, clazz, NOT_EXPIRE); } public String get(String key, long expire) { String value = valueOperations.get(key); if(expire != NOT_EXPIRE){ redisTemplate.expire(key, expire, TimeUnit.SECONDS); } return value; } public String get(String key) { return get(key, NOT_EXPIRE); } public void delete(String key) { redisTemplate.delete(key); } /** * Object转成JSON数据 */ private String toJson(Object object){ if(object instanceof Integer || object instanceof Long || object instanceof Float || object instanceof Double || object instanceof Boolean || object instanceof String){ return String.valueOf(object); } return JSON.toJSONString(object); } /** * JSON数据,转成Object */ private <T> T fromJson(String json, Class<T> clazz){ return JSON.parseObject(json, clazz); } }
2.5 redis切换库支持类 RedisSelectSupport、SelectableRedisTemplate (切换连接在这)
/** * author huangtuL */ public class RedisSelectSupport { private static final ThreadLocal<Integer> SELECT_CONTEXT = new ThreadLocal<>(); public static void select(int db){ SELECT_CONTEXT.set(db); } public static Integer getSelect(){ return SELECT_CONTEXT.get(); } }
import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.core.StringRedisTemplate; /** * author huangtuL */ public class SelectableRedisTemplate extends StringRedisTemplate { @Override protected RedisConnection createRedisConnectionProxy(RedisConnection pm) { return super.createRedisConnectionProxy(pm); } @Override protected RedisConnection preProcessConnection(RedisConnection connection, boolean existingConnection) { Integer db; if((db = RedisSelectSupport.getSelect()) != null){ connection.select(db); } return super.preProcessConnection(connection, existingConnection); } }
2.6 切面类 RedisAspect (主要在这)
import com.example.annotation.RedisSelect; import com.example.exception.RRException; import com.example.redis.RedisSelectSupport; import com.example.redis.SelectableRedisTemplate; import com.example.util.RedisUtils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.stereotype.Component; import java.lang.reflect.Method; /** * Redis切面处理类 * * author huangtuL */ @Aspect @Component public class RedisAspect { private Logger logger = LoggerFactory.getLogger(getClass()); //是否开启redis缓存 true开启 false关闭 @Value("${huangtuL.redis.open: false}") private boolean open; @Autowired private RedisUtils redisUtils; @Value("${spring.redis.database:0}") private int defaultDataBase; @Around("execution(* com.example.util.RedisUtils.*(..))") public Object around(ProceedingJoinPoint point) throws Throwable { Object result = null; if(open){ try{ result = point.proceed(); }catch (Exception e){ logger.error("redis error", e); throw new RRException("Redis服务异常"); } } return result; } @Around("@annotation(com.example.annotation.RedisSelect)") @ConditionalOnBean(SelectableRedisTemplate.class) public Object configRedis(ProceedingJoinPoint point) throws Throwable{ int db = defaultDataBase; try { MethodSignature signature = (MethodSignature) point.getSignature(); Method method = signature.getMethod(); RedisSelect config = method.getAnnotation(RedisSelect.class); if(config != null){ db = config.value(); } RedisSelectSupport.select(db); return point.proceed(); } finally { RedisSelectSupport.select(defaultDataBase); logger.debug("redis reset {} to {}", db, defaultDataBase); } } }
三、测试
3.1 测试类 TestRedisSelect
import com.example.annotation.RedisSelect; import com.example.redis.RedisSelectSupport; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * 测试redis切换库 * author huangtuL */ @RestController @RequestMapping("redis") public class TestRedisSelect { @Autowired private StringRedisTemplate redisTemplate; @RequestMapping("/one") @RedisSelect(1) //选择db1库 public String selectOne(){ String one = redisTemplate.opsForValue().get("one"); return one; } @RequestMapping("/two") @RedisSelect(2) //选择db2库 public String selectTwo(){ String two = redisTemplate.opsForValue().get("two"); return two; } /** * 同一个方法中切换不同的redis库 * @return */ @RequestMapping("/three") @RedisSelect(2) //选择db2库 public String selectThree(){ String two = redisTemplate.opsForValue().get("two"); System.out.println(two); RedisSelectSupport.select(3);//此处切换到db3库 String three = redisTemplate.opsForValue().get("three"); System.out.println(three); return three; } }
3.2 redis中写入测试数据
3.3 测试结果:(打印的 redis reset 表示从哪个库切换回默认的库)
第一个方法,从0切到1库:127.0.0.1:8088/redis-demo/redis/one
第二个方法,从0切到2库:127.0.0.1:8088/redis-demo/redis/two
第三个方法,从0切到2库,同一个方法中再切到3库:127.0.0.1:8088/redis-demo/redis/three
至此,演示完毕。大家看完可以导入项目跑一跑,有疑问可以在评论区留言,看到即回复
【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)