当前位置:   article > 正文

Springboot实现缓存组件(ctgcache、redis)配置动态切换_ctg-cache和redis

ctg-cache和redis

目录

一、需求背景

二、实现缓存组件的动态切换

1.第一步:配置文件新增切换开关

2.第二步:创建ctgcache 缓存条件类

3.第三步:创建redis 缓存条件类

4.第四步:创建缓存切换配置类

5.第五步:创建缓存服务接口

6.第六步:创建ctgcache实现类实现缓存服务接口

7.第七步:创建redis实现类实现缓存服务接口

8.第八步:在程序中注入缓存服务接口使用

三、总结


一、需求背景

        现在有多个springboot项目,但是不同的项目中使用的缓存组件是不一样的,有的项目使用redis,有的项目使用ctgcache,现在需要用同一套代码通过配置开关,在不同的项目中切换这两种缓存。

二、实现缓存组件的动态切换

1.第一步:配置文件新增切换开关
  1. #缓存组件配置
  2. #cache.type=ctgcache
  3. cache.type=redis
2.第二步:创建ctgcache 缓存条件类
  1. package com.gstanzer.supervise.cache;
  2. import org.springframework.context.annotation.Condition;
  3. import org.springframework.context.annotation.ConditionContext;
  4. import org.springframework.core.env.Environment;
  5. import org.springframework.core.type.AnnotatedTypeMetadata;
  6. /**
  7. * ctgcache 缓存条件类
  8. *
  9. * @author: tangbingbing
  10. * @date: 2024/7/22 14:31
  11. */
  12. public class CtgCacheCondition implements Condition {
  13. @Override
  14. public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
  15. // 从 Environment 中获取属性
  16. Environment env = context.getEnvironment();
  17. String cacheType = env.getProperty("cache.type");
  18. // 检查 cache.type 是否与 metadata 中的某个值匹配(这里简单比较字符串)
  19. // 注意:实际应用中可能需要更复杂的逻辑来确定 metadata 中的值
  20. // 这里我们假设 metadata 中没有特定值,仅根据 cache.type 判断
  21. if ("ctgcache".equalsIgnoreCase(cacheType)) {
  22. // 使用 ctgcache
  23. return true;
  24. }
  25. // 如果没有明确指定,或者指定了其他值,我们可以选择默认行为
  26. // 这里假设默认不使用这个 Bean
  27. return false;
  28. }
  29. }

3.第三步:创建redis 缓存条件类
  1. package com.gstanzer.supervise.cache;
  2. import org.springframework.context.annotation.Condition;
  3. import org.springframework.context.annotation.ConditionContext;
  4. import org.springframework.core.env.Environment;
  5. import org.springframework.core.type.AnnotatedTypeMetadata;
  6. /**
  7. * redis 缓存条件类
  8. *
  9. * @author: tangbingbing
  10. * @date: 2024/7/22 14:31
  11. */
  12. public class RedisCondition implements Condition {
  13. @Override
  14. public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
  15. // 从 Environment 中获取属性
  16. Environment env = context.getEnvironment();
  17. String cacheType = env.getProperty("cache.type");
  18. // 检查 cache.type 是否与 metadata 中的某个值匹配(这里简单比较字符串)
  19. // 注意:实际应用中可能需要更复杂的逻辑来确定 metadata 中的值
  20. // 这里我们假设 metadata 中没有特定值,仅根据 cache.type 判断
  21. if ("redis".equalsIgnoreCase(cacheType)) {
  22. // 使用 Redis
  23. return true;
  24. }
  25. // 如果没有明确指定,或者指定了其他值,我们可以选择默认行为
  26. // 这里假设默认不使用这个 Bean
  27. return false;
  28. }
  29. }

4.第四步:创建缓存切换配置类
  1. package com.gstanzer.supervise.cache;
  2. import com.ctg.itrdc.cache.pool.CtgJedisPool;
  3. import com.ctg.itrdc.cache.pool.CtgJedisPoolConfig;
  4. import com.ctg.itrdc.cache.vjedis.jedis.JedisPoolConfig;
  5. import com.fasterxml.jackson.annotation.JsonAutoDetect;
  6. import com.fasterxml.jackson.annotation.PropertyAccessor;
  7. import com.fasterxml.jackson.databind.ObjectMapper;
  8. import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
  9. import org.springframework.beans.factory.annotation.Value;
  10. import org.springframework.context.annotation.Bean;
  11. import org.springframework.context.annotation.Conditional;
  12. import org.springframework.context.annotation.Configuration;
  13. import org.springframework.data.redis.connection.RedisConnectionFactory;
  14. import org.springframework.data.redis.core.RedisTemplate;
  15. import org.springframework.data.redis.listener.RedisMessageListenerContainer;
  16. import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
  17. import org.springframework.data.redis.serializer.RedisSerializer;
  18. import org.springframework.data.redis.serializer.StringRedisSerializer;
  19. import redis.clients.jedis.HostAndPort;
  20. import java.util.ArrayList;
  21. import java.util.List;
  22. /**
  23. * 缓存配置类
  24. *
  25. * @author: tangbingbing
  26. * @date: 2024/7/22 14:28
  27. */
  28. @Configuration
  29. public class CacheConfig {
  30. @Value("${access.cq.redis.host1}")
  31. private String reidsHost1;
  32. @Value("${access.cq.redis.host2}")
  33. private String reidsHost2;
  34. @Value("${access.cq.redis.port}")
  35. private int port;
  36. @Value("${access.cq.redis.password}")
  37. private String password;
  38. @Value("${access.cq.redis.group}")
  39. private String group;
  40. @Value("${access.cq.redis.max-total}")
  41. private int maxTotal;
  42. @Value("${access.cq.redis.max-idle}")
  43. private int maxIdle;
  44. @Value("${access.cq.redis.min-idle}")
  45. private int minIdle;
  46. @Value("${access.cq.redis.max-wait}")
  47. private int maxWait;
  48. @Value("${access.cq.redis.period}")
  49. private int period;
  50. @Value("${access.cq.redis.monitor-timeout}")
  51. private int monitorTimeout;
  52. @Bean
  53. @Conditional(RedisCondition.class)
  54. public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
  55. // 创建并返回RedisTemplate
  56. RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
  57. redisTemplate.setConnectionFactory(factory);
  58. RedisSerializer<String> redisSerializer = new StringRedisSerializer();
  59. redisTemplate.setKeySerializer(redisSerializer);
  60. redisTemplate.setHashKeySerializer(redisSerializer);
  61. // 设置value的序列化器
  62. //使用Jackson 2,将对象序列化为JSON
  63. Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
  64. //json转对象类,不设置默认的会将json转成hashmap
  65. ObjectMapper om = new ObjectMapper();
  66. om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
  67. // json中会显示类型
  68. // om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
  69. jackson2JsonRedisSerializer.setObjectMapper(om);
  70. redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
  71. redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
  72. redisTemplate.afterPropertiesSet();
  73. return redisTemplate;
  74. }
  75. @Bean
  76. @Conditional(RedisCondition.class)
  77. public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory connectionFactory) {
  78. // 创建并返回RedisMessageListenerContainer
  79. RedisMessageListenerContainer container = new RedisMessageListenerContainer();
  80. // 监听所有库的key过期事件
  81. container.setConnectionFactory(connectionFactory);
  82. return container;
  83. }
  84. @Bean
  85. @Conditional(CtgCacheCondition.class)
  86. public CtgJedisPool ctgJedisPool() {
  87. // 创建并返回CtgJedisPool
  88. List<HostAndPort> hostAndPortList = new ArrayList();
  89. HostAndPort host1 = new HostAndPort(reidsHost1, port);
  90. HostAndPort host2 = new HostAndPort(reidsHost2, port);
  91. hostAndPortList.add(host1);
  92. hostAndPortList.add(host2);
  93. GenericObjectPoolConfig poolConfig = new JedisPoolConfig();
  94. poolConfig.setMaxTotal(maxTotal); // 最大连接数(空闲+使用中)
  95. poolConfig.setMaxIdle(maxIdle); //最大空闲连接数
  96. poolConfig.setMinIdle(minIdle); //保持的最小空闲连接数
  97. poolConfig.setMaxWaitMillis(maxWait); //借出连接时最大的等待时间
  98. CtgJedisPoolConfig config = new CtgJedisPoolConfig(hostAndPortList);
  99. config.setDatabase(group)
  100. .setPassword(password)
  101. .setPoolConfig(poolConfig)
  102. .setPeriod(period)
  103. .setMonitorTimeout(monitorTimeout);
  104. CtgJedisPool pool = new CtgJedisPool(config);
  105. return pool;
  106. }
  107. }

5.第五步:创建缓存服务接口
  1. package com.gstanzer.supervise.cache;
  2. /**
  3. * 缓存服务接口
  4. *
  5. * @author: tangbingbing
  6. * @date: 2024/7/22 14:46
  7. */
  8. public interface CacheService {
  9. /**
  10. * 检查缓存中是否存在某个key
  11. *
  12. * @param key
  13. * @return
  14. */
  15. public boolean exists(final String key);
  16. /**
  17. * 获取缓存中对应key的value值
  18. *
  19. * @param key
  20. * @return
  21. */
  22. public String get(final String key);
  23. /**
  24. * 存入值到缓存,并设置有效期
  25. *
  26. * @param key
  27. * @param value
  28. * @param expireTime 有效期,单位s
  29. * @return
  30. */
  31. public boolean set(final String key, String value, int expireTime);
  32. /**
  33. * 存入值到缓存
  34. *
  35. * @param key
  36. * @param value
  37. * @return
  38. */
  39. public boolean set(final String key, String value);
  40. /**
  41. * 删除缓存对应的key值
  42. *
  43. * @param key
  44. * @return
  45. */
  46. public boolean del(final String key);
  47. }

6.第六步:创建ctgcache实现类实现缓存服务接口
  1. package com.gstanzer.supervise.cache;
  2. import com.ctg.itrdc.cache.pool.CtgJedisPool;
  3. import com.ctg.itrdc.cache.pool.ProxyJedis;
  4. import com.gstanzer.supervise.ctgcache.CtgRedisUtil;
  5. import org.slf4j.Logger;
  6. import org.slf4j.LoggerFactory;
  7. import org.springframework.context.annotation.Conditional;
  8. import org.springframework.stereotype.Service;
  9. import javax.annotation.Resource;
  10. /**
  11. * ctgcache 缓存方法实现
  12. *
  13. * @author: tangbingbing
  14. * @date: 2024/7/22 14:48
  15. */
  16. @Service
  17. @Conditional(CtgCacheCondition.class)
  18. public class CtgCacheService implements CacheService {
  19. private static Logger logger = LoggerFactory.getLogger(CtgRedisUtil.class);
  20. @Resource
  21. private CtgJedisPool ctgJedisPool;
  22. /**
  23. * 判断缓存中是否有对应的value
  24. *
  25. * @param key
  26. * @return
  27. */
  28. public boolean exists(final String key) {
  29. Boolean exists = false;
  30. ProxyJedis jedis = new ProxyJedis();
  31. try {
  32. jedis = ctgJedisPool.getResource();
  33. exists = jedis.exists(key);
  34. jedis.close();
  35. } catch (Throwable e) {
  36. logger.error(e.getMessage());
  37. jedis.close();
  38. } finally {
  39. // finally内执行,确保连接归还
  40. try {
  41. jedis.close();
  42. } catch (Throwable ignored) {
  43. }
  44. }
  45. return exists;
  46. }
  47. /**
  48. * 读取缓存
  49. *
  50. * @param key
  51. * @return
  52. */
  53. public String get(final String key) {
  54. String value = null;
  55. ProxyJedis jedis = new ProxyJedis();
  56. try {
  57. jedis = ctgJedisPool.getResource();
  58. value = jedis.get(key);
  59. jedis.close();
  60. } catch (Throwable e) {
  61. logger.error(e.getMessage());
  62. jedis.close();
  63. } finally {
  64. // finally内执行,确保连接归还
  65. try {
  66. jedis.close();
  67. } catch (Throwable ignored) {
  68. }
  69. }
  70. return value;
  71. }
  72. /**
  73. * 写入缓存设置时效时间
  74. *
  75. * @param key
  76. * @param value
  77. * @return
  78. */
  79. public boolean set(final String key, String value, int expireTime) {
  80. Boolean result = false;
  81. ProxyJedis jedis = new ProxyJedis();
  82. try {
  83. jedis = ctgJedisPool.getResource();
  84. jedis.setex(key, expireTime, value);
  85. result = true;
  86. jedis.close();
  87. } catch (Throwable e) {
  88. logger.error(e.getMessage());
  89. jedis.close();
  90. } finally {
  91. // finally内执行,确保连接归还
  92. try {
  93. jedis.close();
  94. } catch (Throwable ignored) {
  95. }
  96. }
  97. return result;
  98. }
  99. /**
  100. * 写入缓存
  101. *
  102. * @param key
  103. * @param value
  104. * @return
  105. */
  106. public boolean set(final String key, String value) {
  107. Boolean result = false;
  108. ProxyJedis jedis = new ProxyJedis();
  109. try {
  110. jedis = ctgJedisPool.getResource();
  111. jedis.set(key, value);
  112. result = true;
  113. jedis.close();
  114. } catch (Throwable e) {
  115. logger.error(e.getMessage());
  116. jedis.close();
  117. } finally {
  118. // finally内执行,确保连接归还
  119. try {
  120. jedis.close();
  121. } catch (Throwable ignored) {
  122. }
  123. }
  124. return result;
  125. }
  126. /**
  127. * 删除缓存
  128. *
  129. * @param key
  130. * @return
  131. */
  132. public boolean del(final String key) {
  133. Boolean result = false;
  134. ProxyJedis jedis = new ProxyJedis();
  135. try {
  136. jedis = ctgJedisPool.getResource();
  137. jedis.del(key);
  138. result = true;
  139. jedis.close();
  140. } catch (Throwable e) {
  141. logger.error(e.getMessage());
  142. jedis.close();
  143. } finally {
  144. // finally内执行,确保连接归还
  145. try {
  146. jedis.close();
  147. } catch (Throwable ignored) {
  148. }
  149. }
  150. return result;
  151. }
  152. }

7.第七步:创建redis实现类实现缓存服务接口
  1. package com.gstanzer.supervise.cache;
  2. import com.gstanzer.supervise.redis.RedisUtils;
  3. import org.slf4j.Logger;
  4. import org.slf4j.LoggerFactory;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.context.annotation.Conditional;
  7. import org.springframework.data.redis.core.RedisTemplate;
  8. import org.springframework.data.redis.core.StringRedisTemplate;
  9. import org.springframework.data.redis.core.ValueOperations;
  10. import org.springframework.stereotype.Service;
  11. import java.io.Serializable;
  12. import java.util.concurrent.TimeUnit;
  13. /**
  14. * reids 缓存方法实现
  15. *
  16. * @author: tangbingbing
  17. * @date: 2024/7/22 14:48
  18. */
  19. @Service
  20. @Conditional(RedisCondition.class)
  21. public class RedisCacheService implements CacheService {
  22. @Autowired
  23. private RedisTemplate redisTemplate;
  24. @Autowired
  25. private StringRedisTemplate stringRedisTemplate;
  26. private static Logger logger = LoggerFactory.getLogger(RedisUtils.class);
  27. /**
  28. * 检查缓存中是否存在某个key
  29. *
  30. * @param key
  31. * @return
  32. */
  33. @Override
  34. public boolean exists(String key) {
  35. return redisTemplate.hasKey(key);
  36. }
  37. /**
  38. * 获取缓存中对应key的value值
  39. *
  40. * @param key
  41. * @return
  42. */
  43. @Override
  44. public String get(String key) {
  45. String result = null;
  46. ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
  47. result = operations.get(key).toString();
  48. return result;
  49. }
  50. /**
  51. * 存入值到缓存,并设置有效期
  52. *
  53. * @param key
  54. * @param value
  55. * @param expireTime 有效期,单位s
  56. * @return
  57. */
  58. @Override
  59. public boolean set(String key, String value, int expireTime) {
  60. boolean result = false;
  61. try {
  62. ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
  63. operations.set(key, value);
  64. redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
  65. result = true;
  66. } catch (Exception e) {
  67. e.printStackTrace();
  68. }
  69. return result;
  70. }
  71. /**
  72. * 存入值到缓存
  73. *
  74. * @param key
  75. * @param value
  76. * @return
  77. */
  78. @Override
  79. public boolean set(String key, String value) {
  80. boolean result = false;
  81. try {
  82. ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
  83. operations.set(key, value);
  84. result = true;
  85. } catch (Exception e) {
  86. e.printStackTrace();
  87. }
  88. return result;
  89. }
  90. /**
  91. * 删除缓存对应的key值
  92. *
  93. * @param key
  94. * @return
  95. */
  96. @Override
  97. public boolean del(String key) {
  98. Boolean result = false;
  99. try {
  100. if (exists(key)) {
  101. redisTemplate.delete(key);
  102. }
  103. result = true;
  104. } catch (Exception e) {
  105. e.printStackTrace();
  106. }
  107. return result;
  108. }
  109. }

8.第八步:在程序中注入缓存服务接口使用
  1. package com.gstanzer.supervise.controller;
  2. import com.gstanzer.supervise.cache.CacheService;
  3. import com.gstanzer.supervise.jwt.PassToken;
  4. import com.gstanzer.supervise.swagger.ApiForBackEndInIAM;
  5. import io.swagger.annotations.Api;
  6. import io.swagger.annotations.ApiOperation;
  7. import io.swagger.annotations.ApiParam;
  8. import lombok.extern.slf4j.Slf4j;
  9. import org.springframework.validation.annotation.Validated;
  10. import org.springframework.web.bind.annotation.PostMapping;
  11. import org.springframework.web.bind.annotation.RequestMapping;
  12. import org.springframework.web.bind.annotation.RequestParam;
  13. import org.springframework.web.bind.annotation.RestController;
  14. import javax.annotation.Resource;
  15. import javax.validation.constraints.NotEmpty;
  16. /**
  17. * 缓存测试 Controller
  18. *
  19. * @author: tangbingbing
  20. * @date: 2023/10/23 16:25
  21. */
  22. @Api(tags = "缓存测试")
  23. @Slf4j
  24. @Validated
  25. @RestController
  26. @RequestMapping(value = "/redis")
  27. public class RedisController {
  28. @Resource
  29. private CacheService cacheService;
  30. @PassToken
  31. @ApiForBackEndInIAM
  32. @ApiOperation(value = "redis测试")
  33. @PostMapping("/test")
  34. public String test(
  35. @RequestParam() @ApiParam(value = "redis键") @NotEmpty(message = "{validator.RedisController.test.key.NotEmpty}") String key
  36. ) {
  37. String res = "获取到redis-value为:空";
  38. if (cacheService.exists(key)){
  39. String value = cacheService.get(key);
  40. res = "获取到redis-value为:" + value;
  41. } else {
  42. cacheService.set(key,"test",60);
  43. res = "未获取到value,重新设置值有效期为60s";
  44. }
  45. return res;
  46. }
  47. }

三、总结

        其实整体实现是一个比较简单的过程,核心是需要了解Springboot中@Conditional注解的应用,希望对大家有所帮助。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/一键难忘520/article/detail/903162
推荐阅读
相关标签
  

闽ICP备14008679号