[flea-frame-cache使用之整合Memcached和Redis接入 源代码]java
Memcached-Java-Client-3.0.2.jargit
<!-- Memcached相关 --> <dependency> <groupId>com.whalin</groupId> <artifactId>Memcached-Java-Client</artifactId> <version>3.0.2</version> </dependency>
jedis-3.0.1.jargithub
<!-- Java redis --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>3.0.1</version> </dependency>
spring-context-4.3.18.RELEASE.jarredis
<!-- Spring相关 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.18.RELEASE</version> </dependency>
spring-context-support-4.3.18.RELEASE.jar算法
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>4.3.18.RELEASE</version> </dependency>
通过上两篇博文的介绍,Memcached 和 Redis 相信不少笔友都能成功的接入应用系统了。随着业务的复杂度上升,缓存的应用场景不断增多,单独的对接一个缓存系统,已经没法知足业务发展要求。spring
本文着眼于整合多套缓存接入:一个缓存 cache 对应一个缓存数据 cache-data,一个缓存数据 cache-data 对应一个缓存组 cache-group,多个缓存服务器 cache-server 关联一个缓存组 cache-group,一个缓存组 cache-group 对应具体的缓存接入实现(目前支持 Memcached 和 Redis)。缓存
下面且听我慢慢道来:服务器
Flea缓存配置文件 ( flea-cache-config.xml),用来整合 Memcached 和 Redis 的相关配置,包含了缓存数据,缓存组,缓存服务器,缓存参数以及其余缓存配置项。app
<?xml version="1.0" encoding="UTF-8"?> <flea-cache-config> <!-- 缓存初始化配置项集 --> <cache-items key="FleaCacheInit" desc="缓存初始化配置项"> <cache-item key="systemName" desc="缓存所属系统名">FleaFrame</cache-item> </cache-items> <!-- Flea缓存建造者配置项集 --> <cache-items key="FleaCacheBuilder" desc="Flea缓存建造者实现"> <cache-item key="MemCached" desc="MemCached的Flea缓存建造者实现">com.huazie.frame.cache.memcached.MemCachedFleaCacheBuilder</cache-item> <cache-item key="Redis" desc="Redis的Flea缓存建造者实现">com.huazie.frame.cache.redis.RedisFleaCacheBuilder</cache-item> </cache-items> <!-- Redis缓存参数集 --> <cache-params key="Redis" desc="Redis缓存配置数据"> <cache-param key="connectionTimeout" desc="Redis客户端socket链接超时时间">2000</cache-param> <cache-param key="soTimeout" desc="Redis客户端socket读写超时时间">2000</cache-param> <cache-param key="hashingAlg" desc="Redis分布式hash算法(1:MURMUR_HASH,2:MD5)">1</cache-param> <cache-param key="pool.maxTotal" desc="Redis客户端Jedis链接池最大链接数">100</cache-param> <cache-param key="pool.maxIdle" desc="Redis客户端Jedis链接池最大空闲链接数">10</cache-param> <cache-param key="pool.minIdle" desc="Redis客户端Jedis链接池最小空闲链接数">0</cache-param> <cache-param key="pool.maxWaitMillis" desc="Redis客户端Jedis链接池获取链接时的最大等待毫秒数">2000</cache-param> </cache-params> <!-- MemCached缓存参数集 --> <cache-params key="MemCached" desc="MemCached缓存配置数据"> <cache-param key="initConn" desc="初始化时对每一个服务器创建的链接数目">20</cache-param> <cache-param key="minConn" desc="每一个服务器创建最小的链接数">20</cache-param> <cache-param key="maxConn" desc="每一个服务器创建最大的链接数">500</cache-param> <cache-param key="maintSleep" desc="自查线程周期进行工做,其每次休眠时间">60000</cache-param> <cache-param key="nagle" desc="Socket的参数,若是是true在写数据时不缓冲,当即发送出去">true</cache-param> <cache-param key="socketTO" desc="Socket阻塞读取数据的超时时间">3000</cache-param> <cache-param key="socketConnectTO" desc="Socket链接超时时间">3000</cache-param> <!-- 0 - native String.hashCode(); 1 - original compatibility 2 - new CRC32 based 3 - MD5 Based --> <cache-param key="hashingAlg" desc="MemCached分布式hash算法">3</cache-param> </cache-params> <!-- Flea缓存数据集 --> <cache-datas> <cache-data type="fleaAuth" desc="Flea Auth缓存数据所在组配置">authGroup</cache-data> <cache-data type="fleaJersey" desc="Flea Jersey缓存数据所在组配置">configGroup</cache-data> <cache-data type="fleaFrame" desc="Flea Frame配置数据所在组配置">configGroup</cache-data> </cache-datas> <!-- Flea缓存组集 --> <cache-groups> <cache-group group="authGroup" desc="Flea权限数据缓存组">MemCached</cache-group> <cache-group group="configGroup" desc="Flea配置数据缓存组">Redis</cache-group> </cache-groups> <!-- Flea缓存服务器集 --> <cache-servers> <cache-server group="authGroup" weight="1" desc="MemCached缓存服务器配置">127.0.0.1:31113</cache-server> <cache-server group="authGroup" weight="1" desc="MemCached缓存服务器配置">127.0.0.1:31114</cache-server> <cache-server group="configGroup" password="huazie123" weight="1" desc="Redis缓存服务器配置">127.0.0.1:10001</cache-server> <cache-server group="configGroup" password="huazie123" weight="1" desc="Redis缓存服务器配置">127.0.0.1:10002</cache-server> <cache-server group="configGroup" password="huazie123" weight="1" desc="Redis缓存服务器配置">127.0.0.1:10003</cache-server> </cache-servers> </flea-cache-config>
Flea缓存定义文件(flea-cache.xml),用来定义各种缓存,其中 key 表示缓存主关键字, type 表示一类缓存数据,expiry 表示缓存生效时长(单位:秒【0:永久】)。socket
<?xml version="1.0" encoding="UTF-8"?> <flea-cache> <caches> <cache key="fleaparadetail" type="fleaFrame" expiry="86400" desc="Flea配置数据缓存" /> <cache key="fleajerseyi18nerrormapping" type="fleaJersey" expiry="86400" desc="Flea Jersey 国际码和错误码映射缓存" /> <cache key="fleajerseyresservice" type="fleaJersey" expiry="86400" desc="Flea Jersey 资源服务缓存" /> <cache key="fleajerseyresclient" type="fleaJersey" expiry="86400" desc="Flea Jersey 资源客户端缓存" /> <cache key="fleajerseyresource" type="fleaJersey" expiry="86400" desc="Flea Jersey 资源缓存" /> <cache key="fleamenufavorites" type="fleaFrame" expiry="0" desc="Flea菜单收藏夹数据缓存" /> </caches> <!-- 其余缓存定义配置文件引入 --> <cache-files> <cache-file> <location>flea/cache/flea-auth-cache.xml</location> <!-- 不包含指定KEY缓存 <executions> <execution>fleaauthuser</execution> <execution>fleaauthprivilege</execution> </executions> --> </cache-file> </cache-files> </flea-cache>
该类一样继承抽象Flea缓存 AbstractFleaCache,实现其定义的抽象方法;内部定义成员变量 fleaCache 用于指定具体的 Flea 缓存实现(这个具体的实现,可参考 Memcached接入 和 Redis接入),实现的三个方法 getNativeValue,putNativeValue,deleteNativeValue 内部采用具体Flea缓存实现fleaCache相应的方法实现读缓存、写缓存,删缓存;从构造方法可见,fleaCache 经过 FleaCacheFactory.getFleaCache(name) ,从Flea缓存工厂中获取。
/** * <p> 核心Flea缓存类 </p> * * @author huazie */ public class CoreFleaCache extends AbstractFleaCache { private AbstractFleaCache fleaCache; // 指定Flea缓存实现 /** * <p> 带参数构造方法,初始化核心Flea缓存类 </p> * * @param name 缓存主关键字 */ public CoreFleaCache(String name) { super(name, CacheConfigManager.getExpiry(name)); // 根据缓存主关键字name获取指定Flea缓存对象 fleaCache = FleaCacheFactory.getFleaCache(name); // 取指定Flea缓存的缓存类型 cache = fleaCache.getCache(); } @Override public Object getNativeValue(String key) { return fleaCache.getNativeValue(key); } @Override public void putNativeValue(String key, Object value, long expiry) { fleaCache.putNativeValue(key, value, expiry); } @Override public void deleteNativeValue(String key) { if (LOGGER.isDebugEnabled()) { LOGGER.debug1(new Object() {}, "KEY = {}", key); } fleaCache.deleteNativeValue(key); } @Override public String getSystemName() { // 获取缓存初始化配置项集之缓存所属系统名配置项 CacheItem cacheItem = CacheConfigManager.getCacheItem(FleaCacheConfigConstants.FLEA_CACHE_INIT, FleaCacheConfigConstants.SYSTEM_NAME); if (ObjectUtils.isEmpty(cacheItem)) { throw new RuntimeException("没法获取缓存系统名,请检查flea-cache-config.xml配置【<cache-item key=" + FleaCacheConfigConstants.SYSTEM_NAME + " >】\""); } return cacheItem.getValue(); } }
该类根据缓存名(即缓存主关键字)所建立的Flea缓存都存入 ConcurrentMap<String, AbstractFleaCache> 中。newCache 方法主要是根据缓存名查找相关缓存 cache,再找到缓存数据 cache-data,接着找到缓存组 cache-group,最后根据缓存组所属的缓存系统,查找缓存配置项 cache-item,获取对应Flea缓存的建造者实现,可参见 flea-cache-config.xml 配置。
/** * <p> Flea Cache 工厂类 </p> * * @author huazie * @version 1.0.0 * @since 1.0.0 */ public class FleaCacheFactory { private static final ConcurrentMap<String, AbstractFleaCache> fleaCacheMap = new ConcurrentHashMap<String, AbstractFleaCache>(); /** * <p> 根据缓存主关键字name获取指定Flea缓存对象 </p> * * @param name 缓存主关键字(对应 flea-cache.xml {@code <cache key="缓存主关键字"></cache>}) * @return Flea缓存对象 * @since 1.0.0 */ public static AbstractFleaCache getFleaCache(String name) { if (!fleaCacheMap.containsKey(name)) { synchronized (fleaCacheMap) { if (!fleaCacheMap.containsKey(name)) { fleaCacheMap.put(name, newFleaCache(name)); } } } return fleaCacheMap.get(name); } /** * <p> 根据缓存主关键字name建立一个Flea缓存对象 </p> * * @param name 缓存主关键字(对应 flea-cache.xml {@code <cache key="缓存主关键字"></cache>}) * @return Flea缓存对象 * @since 1.0.0 */ private static AbstractFleaCache newFleaCache(String name) { // 获取Flea缓存配置信息 Cache cache = CacheConfigManager.getCache(name); if (ObjectUtils.isEmpty(cache)) { throw new RuntimeException("没法初始化Flea缓存,请检查flea-cache.xml配置【<cache key=" + name + " >】"); } // 获取Flea缓存归属数据配置信息 CacheData cacheData = CacheConfigManager.getCacheData(cache.getType()); if (ObjectUtils.isEmpty(cacheData)) { throw new RuntimeException("没法初始化Flea缓存,请检查flea-cache-config.xml配置【<cache-data type=" + cache.getType() + " >】"); } // 获取Flea缓存组 CacheGroup cacheGroup = CacheConfigManager.getCacheGroup(cacheData.getGroup()); if (ObjectUtils.isEmpty(cacheGroup)) { throw new RuntimeException("没法初始化Flea缓存,请检查flea-cache-config.xml配置【<cache-group group=" + cacheData.getGroup() + " >】"); } // 获取缓存系统名 String cacheSystem = cacheGroup.getCache(); // 获取Flea缓存参数 CacheParams cacheParams = CacheConfigManager.getCacheParams(cacheSystem); if (ObjectUtils.isEmpty(cacheParams)) { throw new RuntimeException("没法初始化Flea缓存,请检查flea-cache-config.xml配置【<cache-params key=" + cacheGroup.getCache() + " >】"); } // 获取Flea缓存服务器 List<CacheServer> cacheServerList = CacheConfigManager.getCacheServer(cacheGroup.getGroup()); if (CollectionUtils.isEmpty(cacheServerList)) { throw new RuntimeException("没法初始化Flea缓存,请检查flea-cache-config.xml配置【<cache-server group=" + cacheGroup.getGroup() + " >】"); } // 获取指定缓存系统名对应的Flea缓存建造者 CacheItem cacheItem = CacheConfigManager.getCacheItem(CacheConstants.FleaCacheConfigConstants.FLEA_CACHE_BUILDER, cacheSystem); if (ObjectUtils.isEmpty(cacheItem)) { throw new RuntimeException("没法初始化Flea缓存,请检查flea-cache-config.xml配置【<cache-item key=" + cacheSystem + " >】"); } // Flea缓存建造者 String builder = cacheItem.getValue(); if (ObjectUtils.isEmpty(builder)) { throw new RuntimeException("没法初始化Flea缓存,请检查flea-cache-config.xml配置【<cache-item key=" + cacheSystem + " ></cache-item>】配置项值不能为空"); } AbstractFleaCache fleaCache; try { IFleaCacheBuilder fleaCacheBuilder = (IFleaCacheBuilder) ReflectUtils.newInstance(builder); fleaCache = fleaCacheBuilder.build(name, cacheServerList, cacheParams); } catch (Exception e) { throw new RuntimeException("构建Flea缓存出现异常:\n" + e); } return fleaCache; } }
/** * <p> Flea缓存建造者接口类 </p> * * @author huazie */ public interface IFleaCacheBuilder { /** * <p> 构建Flea缓存对象 </p> * * @param name 缓存主关键字 * @param cacheServerList 缓存服务器集 * @param cacheParams 缓存参数集 * @return Flea缓存对象 */ AbstractFleaCache build(String name, List<CacheServer> cacheServerList, CacheParams cacheParams); }
该类实现 IFleaCacheBuilder,用于构建基于 Memcached 的 Flea 缓存,即建立一个 MemCachedFleaCache。
/** * <p> MemCached的Flea缓存建造者实现 </p> * * @author huazie */ public class MemCachedFleaCacheBuilder implements IFleaCacheBuilder { @Override public AbstractFleaCache build(String name, List<CacheServer> cacheServerList, CacheParams cacheParams) { if (CollectionUtils.isEmpty(cacheServerList)) { return null; } // 获取失效时长 long expiry = CacheConfigManager.getExpiry(name); // 获取MemCached服务器所在组名 String group = cacheServerList.get(0).getGroup(); // 经过组名来获取 MemCached客户端类 MemCachedClient memCachedClient = new MemCachedClient(group); // 获取MemCachedPool,并初始化链接池 MemCachedPool memCachedPool = MemCachedPool.getInstance(group); memCachedPool.initialize(cacheServerList, cacheParams); // 建立一个MemCached Flea缓存类 AbstractFleaCache fleaCache = new MemCachedFleaCache(name, expiry, memCachedClient); return fleaCache; } }
该类实现 IFleaCacheBuilder,用于构建基于Redis的Flea缓存,即建立一个 RedisFleaCache。
/** * <p> Redis的Flea缓存建造者实现 </p> * * @author huazie */ public class RedisFleaCacheBuilder implements IFleaCacheBuilder { @Override public AbstractFleaCache build(String name, List<CacheServer> cacheServerList, CacheParams cacheParams) { if (CollectionUtils.isEmpty(cacheServerList)) { return null; } // 获取失效时长 long expiry = CacheConfigManager.getExpiry(name); // 获取缓存组名 String group = cacheServerList.get(0).getGroup(); // 初始化链接池 RedisPool.getInstance(group).initialize(cacheServerList, cacheParams); // 获取Redis客户端代理类 RedisClient redisClient = RedisClientProxy.getProxyInstance(group); // 建立一个Redis Flea缓存 AbstractFleaCache fleaCache = new RedisFleaCache(name, expiry, redisClient); return fleaCache; } }
核心Flea缓存管理类 CoreFleaCacheManager 继承 AbstractFleaCacheManager ,实现 newCache 方法,用于建立一个核心 Flea 缓存。
/** * <p> 核心Flea缓存管理类 </p> * * @author huazie * @version 1.0.0 * @since 1.0.0 */ public class CoreFleaCacheManager extends AbstractFleaCacheManager { @Override protected AbstractFleaCache newCache(String name, long expiry) { return new CoreFleaCache(name); } }
首先,这里须要按照 Flea缓存配置文件 ( flea-cache-config.xml) 中的缓存服务器 cache-server 中地址部署相应的 Memcached 和 Redis 服务,可参考笔者的 这篇博文。
@Test public void testCoreFleaCache() { try { AbstractFleaCacheManager manager = FleaCacheManagerFactory.getFleaCacheManager(CacheEnum.FleaCore.getName()); AbstractFleaCache cache = manager.getCache("fleaparadetail"); LOGGER.debug("Cache={}", cache); //#### 1. 简单字符串 // cache.put("menu1", "huazie"); // cache.put("menu2", "helloworld"); cache.get("menu1"); cache.get("menu2"); // cache.delete("menu1"); // cache.clear(); cache.getCacheKey(); LOGGER.debug(cache.getCacheName() + ">>>" + cache.getCacheDesc()); } catch (Exception e) { LOGGER.error("Exception:", e); } }
通过上面的介绍,核心Flea缓存相关的内容,基本上算是讲解完毕。在不改变现有业务代码的基础上,相关缓存 cache 能够经过修改其归属的缓存数据类型 type,实现各种缓存数据,多种缓存系统之间的无缝迁移。
核心 Spring 缓存 CoreSpringCache 一样继承抽象 Spring 缓存 AbstractSpringCache,用于对接 Spring;从构造方法可见,该类初始化使用核心Flea缓存类 CoreFleaCache。
/** * <p> 核心Spring缓存类 </p> * * @author huazie */ public class CoreSpringCache extends AbstractSpringCache { /** * <p> 带参数构造方法 </p> * * @param name 缓存主关键字 * @param fleaCache Flea Cache具体实现 */ public CoreSpringCache(String name, IFleaCache fleaCache) { super(name, fleaCache); } /** * <p> 带参数构造方法 </p> * * @param name 缓存主关键字 */ public CoreSpringCache(String name) { super(name, new CoreFleaCache(name)); } }
核心 Spring 缓存管理类 CoreSpringCacheManager 继承抽象 Spring 缓存管理类 AbstractSpringCacheManager,用于对接 Spring;基本实现同核心 Flea 缓存管理类 CoreFleaCacheManager,惟一不一样在于 newCache 的实现,这边是 new 一个核心 Spring 缓存 CoreSpringCache。
/** * <p> 核心Spring缓存管理类 </p> * * @author huazie */ public class CoreSpringCacheManager extends AbstractSpringCacheManager { @Override protected AbstractSpringCache newCache(String name, long expiry) { return new CoreSpringCache(name); } }
<!-- 配置核心Flea缓存管理类 RedisSpringCacheManager --> <bean id="coreSpringCacheManager" class="com.huazie.frame.cache.core.CoreSpringCacheManager" /> <!-- 开启缓存 --> <cache:annotation-driven cache-manager="coreSpringCacheManager" proxy-target-class="true"/>
private ApplicationContext applicationContext; @Before public void init() { applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); LOGGER.debug("ApplicationContext={}", applicationContext); } @Test public void testCoreSpringCache() { try { AbstractSpringCacheManager manager = (CoreSpringCacheManager) applicationContext.getBean("coreSpringCacheManager"); LOGGER.debug("CoreSpringCacheManager={}", manager); AbstractSpringCache cache = manager.getCache("fleaparadetail"); LOGGER.debug("Cache={}", cache); //#### 1. 简单字符串 // cache.put("menu1", "huazie"); // cache.get("menu1"); // cache.get("menu1", String.class); //#### 2. 简单对象(要是能够序列化的对象) // String user = new String("huazie"); // cache.put("user", user); // LOGGER.debug(cache.get("user", String.class)); cache.clear(); //#### 3. List塞对象 // List<String> userList = new ArrayList<String>(); // userList.add("huazie"); // userList.add("lgh"); // cache.put("user_list", userList); // LOGGER.debug(cache.get("user_list",userList.getClass()).toString()); } catch (Exception e) { LOGGER.error("Exception:", e); } }
@Cacheable 使用,value 为缓存名,也做缓存主关键字, key 为具体的缓存键
@Cacheable(value = "fleaparadetail", key = "#paraType + '_' + #paraCode") public FleaParaDetail getParaDetail(String paraType, String paraCode) throws Exception { List<FleaParaDetail> fleaParaDetails = fleaParaDetailDao.getParaDetail(paraType, paraCode); FleaParaDetail fleaParaDetailValue = null; if (CollectionUtils.isNotEmpty(fleaParaDetails)) { fleaParaDetailValue = fleaParaDetails.get(0); } return fleaParaDetailValue; }
到目前为止,整合 Memcached 和 Redis 接入的工做已经所有完成,相信各位已经可以接入系统~~~