SpringBoot實現(xiàn)緩存組件配置動態(tài)切換的步驟詳解
一、需求背景
現(xiàn)在有多個springboot項目,但是不同的項目中使用的緩存組件是不一樣的,有的項目使用redis,有的項目使用ctgcache,現(xiàn)在需要用同一套代碼通過配置開關(guān),在不同的項目中切換這兩種緩存。
二、實現(xiàn)緩存組件的動態(tài)切換
1.第一步:配置文件新增切換開關(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 中的某個值匹配(這里簡單比較字符串) // 注意:實際應(yīng)用中可能需要更復(fù)雜的邏輯來確定 metadata 中的值 // 這里我們假設(shè) metadata 中沒有特定值,僅根據(jù) cache.type 判斷 if ("ctgcache".equalsIgnoreCase(cacheType)) { // 使用 ctgcache return true; } // 如果沒有明確指定,或者指定了其他值,我們可以選擇默認(rèn)行為 // 這里假設(shè)默認(rèn)不使用這個 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 中的某個值匹配(這里簡單比較字符串) // 注意:實際應(yīng)用中可能需要更復(fù)雜的邏輯來確定 metadata 中的值 // 這里我們假設(shè) metadata 中沒有特定值,僅根據(jù) cache.type 判斷 if ("redis".equalsIgnoreCase(cacheType)) { // 使用 Redis return true; } // 如果沒有明確指定,或者指定了其他值,我們可以選擇默認(rèn)行為 // 這里假設(shè)默認(rèn)不使用這個 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,將對象序列化為JSON Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); //json轉(zhuǎn)對象類,不設(shè)置默認(rèn)的會將json轉(zhuǎn)成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) { // 創(chuàng)建并返回RedisMessageListenerContainer RedisMessageListenerContainer container = new RedisMessageListenerContainer(); // 監(jiān)聽所有庫的key過期事件 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); //借出連接時最大的等待時間 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 { /** * 檢查緩存中是否存在某個key * * @param key * @return */ public boolean exists(final String key); /** * 獲取緩存中對應(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); /** * 刪除緩存對應(yīng)的key值 * * @param key * @return */ public boolean del(final String key); }
6.第六步:創(chuàng)建ctgcache實現(xiàn)類實現(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 緩存方法實現(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; /** * 判斷緩存中是否有對應(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è)置時效時間 * * @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實現(xiàn)類實現(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 緩存方法實現(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); /** * 檢查緩存中是否存在某個key * * @param key * @return */ @Override public boolean exists(String key) { return redisTemplate.hasKey(key); } /** * 獲取緩存中對應(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; } /** * 刪除緩存對應(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; /** * 緩存測試 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,重新設(shè)置值有效期為60s"; } return res; } }
三、總結(jié)
其實整體實現(xiàn)是一個比較簡單的過程,核心是需要了解Springboot中@Conditional注解的應(yīng)用,希望對大家有所幫助。
到此這篇關(guān)于SpringBoot實現(xiàn)緩存組件配置動態(tài)切換的步驟詳解的文章就介紹到這了,更多相關(guān)SpringBoot緩存組件動態(tài)切換內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Spring Cloud Zuul中路由配置細(xì)節(jié)
本篇文章主要介紹了詳解Spring Cloud Zuul中路由配置細(xì)節(jié),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-10-10java streamfilter list 過濾的實現(xiàn)
Java Stream API中的filter方法是過濾List集合中元素的一個強大工具,可以輕松地根據(jù)自定義條件篩選出符合要求的元素,本文就來介紹一下java streamfilter list 過濾的實現(xiàn),感興趣的可以了解一下2025-03-03Java操作redis實現(xiàn)增刪查改功能的方法示例
這篇文章主要介紹了Java操作redis實現(xiàn)增刪查改功能的方法,涉及java操作redis數(shù)據(jù)庫的連接、設(shè)置、增刪改查、釋放資源等相關(guān)操作技巧,需要的朋友可以參考下2017-08-08基于spring+quartz的分布式定時任務(wù)框架實現(xiàn)
在Spring中的定時任務(wù)功能,最好的辦法當(dāng)然是使用Quartz來實現(xiàn)。這篇文章主要介紹了基于spring+quartz的分布式定時任務(wù)框架實現(xiàn),有興趣的可以了解一下。2017-01-01mybaties plus實體類設(shè)置typeHandler不生效的解決
這篇文章主要介紹了mybaties plus實體類設(shè)置typeHandler不生效的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08springboot2.2.2集成dubbo的實現(xiàn)方法
這篇文章主要介紹了springboot2.2.2集成dubbo的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01