SpringBoot實(shí)現(xiàn)緩存組件配置動(dòng)態(tài)切換的步驟詳解
一、需求背景
現(xiàn)在有多個(gè)springboot項(xiàng)目,但是不同的項(xiàng)目中使用的緩存組件是不一樣的,有的項(xiàng)目使用redis,有的項(xiàng)目使用ctgcache,現(xiàn)在需要用同一套代碼通過(guò)配置開(kāi)關(guān),在不同的項(xiàng)目中切換這兩種緩存。
二、實(shí)現(xiàn)緩存組件的動(dòng)態(tài)切換
1.第一步:配置文件新增切換開(kāi)關(guān)
#緩存組件配置 #cache.type=ctgcache cache.type=redis
2.第二步:創(chuàng)建ctgcache 緩存條件類
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 中的某個(gè)值匹配(這里簡(jiǎn)單比較字符串)
// 注意:實(shí)際應(yīng)用中可能需要更復(fù)雜的邏輯來(lái)確定 metadata 中的值
// 這里我們假設(shè) metadata 中沒(méi)有特定值,僅根據(jù) cache.type 判斷
if ("ctgcache".equalsIgnoreCase(cacheType)) {
// 使用 ctgcache
return true;
}
// 如果沒(méi)有明確指定,或者指定了其他值,我們可以選擇默認(rèn)行為
// 這里假設(shè)默認(rèn)不使用這個(gè) Bean
return false;
}
}3.第三步:創(chuàng)建redis 緩存條件類
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 中的某個(gè)值匹配(這里簡(jiǎn)單比較字符串)
// 注意:實(shí)際應(yīng)用中可能需要更復(fù)雜的邏輯來(lái)確定 metadata 中的值
// 這里我們假設(shè) metadata 中沒(méi)有特定值,僅根據(jù) cache.type 判斷
if ("redis".equalsIgnoreCase(cacheType)) {
// 使用 Redis
return true;
}
// 如果沒(méi)有明確指定,或者指定了其他值,我們可以選擇默認(rèn)行為
// 這里假設(shè)默認(rèn)不使用這個(gè) Bean
return false;
}
}4.第四步:創(chuàng)建緩存切換配置類
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) {
// 創(chuàng)建并返回RedisTemplate
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factory);
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(redisSerializer);
redisTemplate.setHashKeySerializer(redisSerializer);
// 設(shè)置value的序列化器
//使用Jackson 2,將對(duì)象序列化為JSON
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
//json轉(zhuǎn)對(duì)象類,不設(shè)置默認(rèn)的會(huì)將json轉(zhuǎn)成hashmap
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// json中會(huì)顯示類型
// 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) {
// 創(chuàng)建并返回RedisMessageListenerContainer
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
// 監(jiān)聽(tīng)所有庫(kù)的key過(guò)期事件
container.setConnectionFactory(connectionFactory);
return container;
}
@Bean
@Conditional(CtgCacheCondition.class)
public CtgJedisPool ctgJedisPool() {
// 創(chuàng)建并返回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); // 最大連接數(shù)(空閑+使用中)
poolConfig.setMaxIdle(maxIdle); //最大空閑連接數(shù)
poolConfig.setMinIdle(minIdle); //保持的最小空閑連接數(shù)
poolConfig.setMaxWaitMillis(maxWait); //借出連接時(shí)最大的等待時(shí)間
CtgJedisPoolConfig config = new CtgJedisPoolConfig(hostAndPortList);
config.setDatabase(group)
.setPassword(password)
.setPoolConfig(poolConfig)
.setPeriod(period)
.setMonitorTimeout(monitorTimeout);
CtgJedisPool pool = new CtgJedisPool(config);
return pool;
}
}5.第五步:創(chuàng)建緩存服務(wù)接口
package com.gstanzer.supervise.cache;
/**
* 緩存服務(wù)接口
*
* @author: tangbingbing
* @date: 2024/7/22 14:46
*/
public interface CacheService {
/**
* 檢查緩存中是否存在某個(gè)key
*
* @param key
* @return
*/
public boolean exists(final String key);
/**
* 獲取緩存中對(duì)應(yīng)key的value值
*
* @param key
* @return
*/
public String get(final String key);
/**
* 存入值到緩存,并設(shè)置有效期
*
* @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);
/**
* 刪除緩存對(duì)應(yīng)的key值
*
* @param key
* @return
*/
public boolean del(final String key);
}6.第六步:創(chuàng)建ctgcache實(shí)現(xiàn)類實(shí)現(xiàn)緩存服務(wù)接口
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 緩存方法實(shí)現(xiàn)
*
* @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;
/**
* 判斷緩存中是否有對(duì)應(yīng)的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內(nèi)執(zhí)行,確保連接歸還
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內(nèi)執(zhí)行,確保連接歸還
try {
jedis.close();
} catch (Throwable ignored) {
}
}
return value;
}
/**
* 寫入緩存設(shè)置時(shí)效時(shí)間
*
* @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內(nèi)執(zhí)行,確保連接歸還
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內(nèi)執(zhí)行,確保連接歸還
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內(nèi)執(zhí)行,確保連接歸還
try {
jedis.close();
} catch (Throwable ignored) {
}
}
return result;
}
}7.第七步:創(chuàng)建redis實(shí)現(xiàn)類實(shí)現(xiàn)緩存服務(wù)接口
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 緩存方法實(shí)現(xiàn)
*
* @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);
/**
* 檢查緩存中是否存在某個(gè)key
*
* @param key
* @return
*/
@Override
public boolean exists(String key) {
return redisTemplate.hasKey(key);
}
/**
* 獲取緩存中對(duì)應(yīng)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;
}
/**
* 存入值到緩存,并設(shè)置有效期
*
* @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;
}
/**
* 刪除緩存對(duì)應(yīng)的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;
}
}8.第八步:在程序中注入緩存服務(wù)接口使用
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;
/**
* 緩存測(cè)試 Controller
*
* @author: tangbingbing
* @date: 2023/10/23 16:25
*/
@Api(tags = "緩存測(cè)試")
@Slf4j
@Validated
@RestController
@RequestMapping(value = "/redis")
public class RedisController {
@Resource
private CacheService cacheService;
@PassToken
@ApiForBackEndInIAM
@ApiOperation(value = "redis測(cè)試")
@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,重新設(shè)置值有效期為60s";
}
return res;
}
}三、總結(jié)
其實(shí)整體實(shí)現(xiàn)是一個(gè)比較簡(jiǎn)單的過(guò)程,核心是需要了解Springboot中@Conditional注解的應(yīng)用,希望對(duì)大家有所幫助。
到此這篇關(guān)于SpringBoot實(shí)現(xiàn)緩存組件配置動(dòng)態(tài)切換的步驟詳解的文章就介紹到這了,更多相關(guān)SpringBoot緩存組件動(dòng)態(tài)切換內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)源切換的項(xiàng)目實(shí)踐
- SpringBoot實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)源切換的方法總結(jié)
- 使用SpringBoot動(dòng)態(tài)切換數(shù)據(jù)源的實(shí)現(xiàn)方式
- SpringBoot+ThreadLocal+AbstractRoutingDataSource實(shí)現(xiàn)動(dòng)態(tài)切換數(shù)據(jù)源
- springboot使用DynamicDataSource動(dòng)態(tài)切換數(shù)據(jù)源的實(shí)現(xiàn)過(guò)程
相關(guān)文章
詳解Spring Cloud Zuul中路由配置細(xì)節(jié)
本篇文章主要介紹了詳解Spring Cloud Zuul中路由配置細(xì)節(jié),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-10-10
java streamfilter list 過(guò)濾的實(shí)現(xiàn)
Java Stream API中的filter方法是過(guò)濾List集合中元素的一個(gè)強(qiáng)大工具,可以輕松地根據(jù)自定義條件篩選出符合要求的元素,本文就來(lái)介紹一下java streamfilter list 過(guò)濾的實(shí)現(xiàn),感興趣的可以了解一下2025-03-03
Java操作redis實(shí)現(xiàn)增刪查改功能的方法示例
這篇文章主要介紹了Java操作redis實(shí)現(xiàn)增刪查改功能的方法,涉及java操作redis數(shù)據(jù)庫(kù)的連接、設(shè)置、增刪改查、釋放資源等相關(guān)操作技巧,需要的朋友可以參考下2017-08-08
基于spring+quartz的分布式定時(shí)任務(wù)框架實(shí)現(xiàn)
在Spring中的定時(shí)任務(wù)功能,最好的辦法當(dāng)然是使用Quartz來(lái)實(shí)現(xiàn)。這篇文章主要介紹了基于spring+quartz的分布式定時(shí)任務(wù)框架實(shí)現(xiàn),有興趣的可以了解一下。2017-01-01
mybaties plus實(shí)體類設(shè)置typeHandler不生效的解決
這篇文章主要介紹了mybaties plus實(shí)體類設(shè)置typeHandler不生效的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08
java向上轉(zhuǎn)型發(fā)生的時(shí)機(jī)知識(shí)點(diǎn)詳解
在本篇文章里小編給大家整理分享的是關(guān)于java向上轉(zhuǎn)型發(fā)生的時(shí)機(jī)知識(shí)點(diǎn)內(nèi)容,有興趣的讀者們可以參考下。2021-05-05
springboot2.2.2集成dubbo的實(shí)現(xiàn)方法
這篇文章主要介紹了springboot2.2.2集成dubbo的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01
Java使用Tess4J實(shí)現(xiàn)圖像識(shí)別方式
這篇文章主要介紹了Java使用Tess4J實(shí)現(xiàn)圖像識(shí)別方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10

