现在有多个springboot项目,但是不同的项目中使用的缓存组件是不一样的,有的项目使用redis,有的项目使用ctgcache,现在需要用同一套代码通过配置开关,在不同的项目中切换这两种缓存。
1 2 3 |
#缓存组件配置 #cache.type=ctgcache cache.type=redis |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
package com.gstanzer.supervise.cache;
import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotatedTypeMetadata;
/** * ctgcache 缓存条件类 * * @author: tangbingbing * @date: 2024/7/22 14:31 */ public class CtgCacheCondition implements Condition {
@Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { // 从 Environment 中获取属性 Environment env = context.getEnvironment(); String cacheType = env.getProperty("cache.type");
// 检查 cache.type 是否与 metadata 中的某个值匹配(这里简单比较字符串) // 注意:实际应用中可能需要更复杂的逻辑来确定 metadata 中的值 // 这里我们假设 metadata 中没有特定值,仅根据 cache.type 判断 if ("ctgcache".equalsIgnoreCase(cacheType)) { // 使用 ctgcache return true; }
// 如果没有明确指定,或者指定了其他值,我们可以选择默认行为 // 这里假设默认不使用这个 Bean return false; }
} |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
package com.gstanzer.supervise.cache;
import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotatedTypeMetadata;
/** * redis 缓存条件类 * * @author: tangbingbing * @date: 2024/7/22 14:31 */ public class RedisCondition implements Condition {
@Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { // 从 Environment 中获取属性 Environment env = context.getEnvironment(); String cacheType = env.getProperty("cache.type");
// 检查 cache.type 是否与 metadata 中的某个值匹配(这里简单比较字符串) // 注意:实际应用中可能需要更复杂的逻辑来确定 metadata 中的值 // 这里我们假设 metadata 中没有特定值,仅根据 cache.type 判断 if ("redis".equalsIgnoreCase(cacheType)) { // 使用 Redis return true; }
// 如果没有明确指定,或者指定了其他值,我们可以选择默认行为 // 这里假设默认不使用这个 Bean return false; }
} |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
package com.gstanzer.supervise.cache;
import com.ctg.itrdc.cache.pool.CtgJedisPool; import com.ctg.itrdc.cache.pool.CtgJedisPoolConfig; import com.ctg.itrdc.cache.vjedis.jedis.JedisPoolConfig; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.listener.RedisMessageListenerContainer; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; import redis.clients.jedis.HostAndPort;
import java.util.ArrayList; import java.util.List;
/** * 缓存配置类 * * @author: tangbingbing * @date: 2024/7/22 14:28 */ @Configuration public class CacheConfig {
@Value("${access.cq.redis.host1}") private String reidsHost1;
@Value("${access.cq.redis.host2}") private String reidsHost2;
@Value("${access.cq.redis.port}") private int port;
@Value("${access.cq.redis.password}") private String password;
@Value("${access.cq.redis.group}") private String group;
@Value("${access.cq.redis.max-total}") private int maxTotal;
@Value("${access.cq.redis.max-idle}") private int maxIdle;
@Value("${access.cq.redis.min-idle}") private int minIdle;
@Value("${access.cq.redis.max-wait}") private int maxWait;
@Value("${access.cq.redis.period}") private int period;
@Value("${access.cq.redis.monitor-timeout}") private int monitorTimeout;
@Bean @Conditional(RedisCondition.class) public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { // 创建并返回RedisTemplate RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(factory);
RedisSerializer<String> redisSerializer = new StringRedisSerializer(); redisTemplate.setKeySerializer(redisSerializer); redisTemplate.setHashKeySerializer(redisSerializer);
// 设置value的序列化器 //使用Jackson 2,将对象序列化为JSON Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); //json转对象类,不设置默认的会将json转成hashmap ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// json中会显示类型 // om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); redisTemplate.afterPropertiesSet(); return redisTemplate; }
@Bean @Conditional(RedisCondition.class) public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory connectionFactory) { // 创建并返回RedisMessageListenerContainer RedisMessageListenerContainer container = new RedisMessageListenerContainer(); // 监听所有库的key过期事件 container.setConnectionFactory(connectionFactory); return container; }
@Bean @Conditional(CtgCacheCondition.class) public CtgJedisPool ctgJedisPool() { // 创建并返回CtgJedisPool List<HostAndPort> hostAndPortList = new ArrayList(); HostAndPort host1 = new HostAndPort(reidsHost1, port); HostAndPort host2 = new HostAndPort(reidsHost2, port); hostAndPortList.add(host1); hostAndPortList.add(host2);
GenericObjectPoolConfig poolConfig = new JedisPoolConfig(); poolConfig.setMaxTotal(maxTotal); // 最大连接数(空闲+使用中) poolConfig.setMaxIdle(maxIdle); //最大空闲连接数 poolConfig.setMinIdle(minIdle); //保持的最小空闲连接数 poolConfig.setMaxWaitMillis(maxWait); //借出连接时最大的等待时间
CtgJedisPoolConfig config = new CtgJedisPoolConfig(hostAndPortList); config.setDatabase(group) .setPassword(password) .setPoolConfig(poolConfig) .setPeriod(period) .setMonitorTimeout(monitorTimeout);
CtgJedisPool pool = new CtgJedisPool(config); return pool; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
package com.gstanzer.supervise.cache;
/** * 缓存服务接口 * * @author: tangbingbing * @date: 2024/7/22 14:46 */ public interface CacheService {
/** * 检查缓存中是否存在某个key * * @param key * @return */ public boolean exists(final String key);
/** * 获取缓存中对应key的value值 * * @param key * @return */ public String get(final String key);
/** * 存入值到缓存,并设置有效期 * * @param key * @param value * @param expireTime 有效期,单位s * @return */ public boolean set(final String key, String value, int expireTime);
/** * 存入值到缓存 * * @param key * @param value * @return */ public boolean set(final String key, String value);
/** * 删除缓存对应的key值 * * @param key * @return */ public boolean del(final String key);
} |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
package com.gstanzer.supervise.cache;
import com.ctg.itrdc.cache.pool.CtgJedisPool; import com.ctg.itrdc.cache.pool.ProxyJedis; import com.gstanzer.supervise.ctgcache.CtgRedisUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Conditional; import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/** * ctgcache 缓存方法实现 * * @author: tangbingbing * @date: 2024/7/22 14:48 */ @Service @Conditional(CtgCacheCondition.class) public class CtgCacheService implements CacheService {
private static Logger logger = LoggerFactory.getLogger(CtgRedisUtil.class);
@Resource private CtgJedisPool ctgJedisPool;
/** * 判断缓存中是否有对应的value * * @param key * @return */ public boolean exists(final String key) { Boolean exists = false; ProxyJedis jedis = new ProxyJedis(); try { jedis = ctgJedisPool.getResource(); exists = jedis.exists(key); jedis.close(); } catch (Throwable e) { logger.error(e.getMessage()); jedis.close(); } finally { // finally内执行,确保连接归还 try { jedis.close(); } catch (Throwable ignored) {
} } return exists; }
/** * 读取缓存 * * @param key * @return */ public String get(final String key) { String value = null; ProxyJedis jedis = new ProxyJedis(); try { jedis = ctgJedisPool.getResource(); value = jedis.get(key); jedis.close(); } catch (Throwable e) { logger.error(e.getMessage()); jedis.close(); } finally { // finally内执行,确保连接归还 try { jedis.close(); } catch (Throwable ignored) {
} } return value; }
/** * 写入缓存设置时效时间 * * @param key * @param value * @return */ public boolean set(final String key, String value, int expireTime) { Boolean result = false; ProxyJedis jedis = new ProxyJedis(); try { jedis = ctgJedisPool.getResource(); jedis.setex(key, expireTime, value); result = true; jedis.close(); } catch (Throwable e) { logger.error(e.getMessage()); jedis.close(); } finally { // finally内执行,确保连接归还 try { jedis.close(); } catch (Throwable ignored) {
} } return result; }
/** * 写入缓存 * * @param key * @param value * @return */ public boolean set(final String key, String value) { Boolean result = false; ProxyJedis jedis = new ProxyJedis(); try { jedis = ctgJedisPool.getResource(); jedis.set(key, value); result = true; jedis.close(); } catch (Throwable e) { logger.error(e.getMessage()); jedis.close(); } finally { // finally内执行,确保连接归还 try { jedis.close(); } catch (Throwable ignored) {
} } return result; }
/** * 删除缓存 * * @param key * @return */ public boolean del(final String key) { Boolean result = false; ProxyJedis jedis = new ProxyJedis(); try { jedis = ctgJedisPool.getResource(); jedis.del(key); result = true; jedis.close(); } catch (Throwable e) { logger.error(e.getMessage()); jedis.close(); } finally { // finally内执行,确保连接归还 try { jedis.close(); } catch (Throwable ignored) {
} } return result; }
} |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
package com.gstanzer.supervise.cache;
import com.gstanzer.supervise.redis.RedisUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Conditional; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.stereotype.Service;
import java.io.Serializable; import java.util.concurrent.TimeUnit;
/** * reids 缓存方法实现 * * @author: tangbingbing * @date: 2024/7/22 14:48 */ @Service @Conditional(RedisCondition.class) public class RedisCacheService implements CacheService {
@Autowired private RedisTemplate redisTemplate;
@Autowired private StringRedisTemplate stringRedisTemplate;
private static Logger logger = LoggerFactory.getLogger(RedisUtils.class);
/** * 检查缓存中是否存在某个key * * @param key * @return */ @Override public boolean exists(String key) { return redisTemplate.hasKey(key); }
/** * 获取缓存中对应key的value值 * * @param key * @return */ @Override public String get(String key) { String result = null; ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); result = operations.get(key).toString(); return result; }
/** * 存入值到缓存,并设置有效期 * * @param key * @param value * @param expireTime 有效期,单位s * @return */ @Override public boolean set(String key, String value, int expireTime) { boolean result = false; try { ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); operations.set(key, value); redisTemplate.expire(key, expireTime, TimeUnit.SECONDS); result = true; } catch (Exception e) { e.printStackTrace(); } return result; }
/** * 存入值到缓存 * * @param key * @param value * @return */ @Override public boolean set(String key, String value) { boolean result = false; try { ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue(); operations.set(key, value); result = true; } catch (Exception e) { e.printStackTrace(); } return result; }
/** * 删除缓存对应的key值 * * @param key * @return */ @Override public boolean del(String key) { Boolean result = false; try { if (exists(key)) { redisTemplate.delete(key); } result = true; } catch (Exception e) { e.printStackTrace(); } return result; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
package com.gstanzer.supervise.controller;
import com.gstanzer.supervise.cache.CacheService; import com.gstanzer.supervise.jwt.PassToken; import com.gstanzer.supervise.swagger.ApiForBackEndInIAM; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource; import javax.validation.constraints.NotEmpty;
/** * 缓存测试 Controller * * @author: tangbingbing * @date: 2023/10/23 16:25 */ @Api(tags = "缓存测试") @Slf4j @Validated @RestController @RequestMapping(value = "/redis") public class RedisController {
@Resource private CacheService cacheService;
@PassToken @ApiForBackEndInIAM @ApiOperation(value = "redis测试") @PostMapping("/test") public String test( @RequestParam() @ApiParam(value = "redis键") @NotEmpty(message = "{validator.RedisController.test.key.NotEmpty}") String key ) { String res = "获取到redis-value为:空"; if (cacheService.exists(key)){ String value = cacheService.get(key); res = "获取到redis-value为:" + value; } else { cacheService.set(key,"test",60); res = "未获取到value,重新设置值有效期为60s"; } return res; } } |
其实整体实现是一个比较简单的过程,核心是需要了解Springboot中@Conditional注解的应用,希望对大家有所帮助。