flea-frame-cache使用之Memcached接入 源代码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>
spring-context-4.3.18.RELEASE.jargithub
<!-- 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>
/** * <p> 自定义Cache接口类(主要定义了一些增删改查的方法) </p> * * @author huazie */ public interface IFleaCache { /** * <p> 读缓存 </p> * * @param key 数据键关键字 * @return 数据值 */ Object get(String key); /** * <p> 写缓存 </p> * * @param key 数据键关键字 * @param value 数据值 */ void put(String key, Object value); /** * <p> 清空全部缓存 </p> */ void clear(); /** * <p> 删除指定数据键关键字对应的缓存 </p> * * @param key 数据键关键字 */ void delete(String key); /** * <p> 获取 记录当前Cache全部数据键关键字 的Set集合 </p> * * @return 数据键key的集合 */ Set<String> getCacheKey(); /** * <p> 获取缓存所属系统名 </p> * * @return 缓存所属系统名 */ String getSystemName(); }
/** * <p> 抽象Flea Cache类 </p> * * @author huazie */ public abstract class AbstractFleaCache implements IFleaCache { private final String name; // 缓存数据主关键字 private final long expiry; // 有效期(单位:秒) protected CacheEnum cache; // 缓存实现 public AbstractFleaCache(String name, long expiry) { this.name = name; this.expiry = expiry; } @Override public Object get(String key) { Object value = null; try { value = getNativeValue(getNativeKey(key)); } catch (Exception e) { } return value; } @Override public void put(String key, Object value) { if (ObjectUtils.isEmpty(value)) return; try { putNativeValue(getNativeKey(key), value, expiry); // 将指定Cache的key添加到Set集合,并存于缓存中 addCacheKey(key); } catch (Exception e) { } } @Override public void clear() { Set<String> keySet = getCacheKey(); if (CollectionUtils.isNotEmpty(keySet)) { for (String key : keySet) { deleteNativeValue(getNativeKey(key)); } // 删除 记录当前Cache全部数据键关键字 的缓存 deleteCacheAllKey(); } } @Override public void delete(String key) { try { deleteNativeValue(getNativeKey(key)); // 从 记录当前Cache全部数据键关键字 的缓存中 删除指定数据键关键字key deleteCacheKey(key); } catch (Exception e) { } } /** * <p> 将指定数据键关键字{@code key}记录到当前Cache全部数据键关键字的缓存中 </p> * * @param key 指定Cache的数据键关键字 */ private void addCacheKey(String key) { Set<String> keySet = getCacheKey(); if (CollectionUtils.isEmpty(keySet)) { keySet = new HashSet<>(); } if (!keySet.contains(key)) { // 只有其中不存在,才从新设置 keySet.add(key); putNativeValue(getNativeCacheKey(name), keySet, CommonConstants.NumeralConstants.ZERO); } } /** * <p> 从 记录当前Cache全部数据键关键字 的缓存中 删除指定数据键关键字{@code key} </p> * * @param key 指定Cache的数据键关键字 */ private void deleteCacheKey(String key) { Set<String> keySet = getCacheKey(); if (CollectionUtils.isNotEmpty(keySet)) { // 存在待删除的数据键关键字 if (keySet.contains(key)) { if (CommonConstants.NumeralConstants.INT_ONE == keySet.size()) { deleteCacheAllKey(); // 直接将记录当前Cache全部数据键关键字的缓存从缓存中清空 } else { // 将数据键关键字从Set集合中删除 keySet.remove(key); // 从新覆盖当前Cache全部数据键关键字的缓存信息 putNativeValue(getNativeCacheKey(name), keySet, CommonConstants.NumeralConstants.ZERO); } } } } /** * <p> 删除 记录当前Cache全部数据键关键字 的缓存 </p> */ private void deleteCacheAllKey() { try { deleteNativeValue(getNativeCacheKey(name)); } catch (Exception e) { } } @Override @SuppressWarnings(value = "unchecked") public Set<String> getCacheKey() { Set<String> keySet = null; Object keySetObj = getNativeValue(getNativeCacheKey(name)); if (ObjectUtils.isNotEmpty(keySetObj) && keySetObj instanceof Set) { keySet = (Set<String>) keySetObj; } return keySet; } /** * <p> 获取缓存值 </p> * * @param key 缓存数据键关键字 * @return 缓存值 */ public abstract Object getNativeValue(String key); /** * <p> 添加缓存数据 </p> * * @param key 缓存数据键关键字 * @param value 缓存值 * @param expiry 失效时间(单位:秒) */ public abstract void putNativeValue(String key, Object value, long expiry); /** * <p> 删除指定缓存数据 </p> * * @param key 缓存数据键关键字 */ public abstract void deleteNativeValue(String key); /** * <p> 获取缓存所属系统名 </p> * * @return 缓存所属系统名 */ public abstract String getSystemName(); /** * <p> 获取实际存储的缓存键(缓存所属系统名 + 缓存名(缓存主关键字) + 缓存数据键(缓存数据关键字)) </p> * * @param key 缓存数据键关键字 * @return 实际存储的缓存键 */ private String getNativeKey(String key) { return StringUtils.strCat(getNativeCacheKey(name), CommonConstants.SymbolConstants.UNDERLINE, key); } /** * <p> 获取缓存主键(包含缓存所属系统名 + 缓存名(缓存主关键字)) </p> * * @param name 缓存名(缓存主关键字) * @return 缓存主键(缓存所属系统名 + 缓存名(缓存主关键字)) */ protected String getNativeCacheKey(String name) { return StringUtils.strCat(getSystemName(), CommonConstants.SymbolConstants.UNDERLINE, name); } // ...省略一些get方法 }
该类实现了IFleaCache接口,同时定义了三个抽象方法 :spring
public abstract Object getNativeValue(String key); public abstract void putNativeValue(String key, Object value, long expiry); public abstract void deleteNativeValue(String key);
这三个抽象方法由子类实现具体的读,写,删除缓存的原始操做缓存
该类继承 AbstractFleaCache,实现Memcached缓存的接入使用;bash
/** * <p> MemCached Flea缓存类 </p> * * @author huazie */ public class MemCachedFleaCache extends AbstractFleaCache { private final MemCachedClient memCachedClient; // MemCached客户端 /** * <p> 带参数的构造方法,初始化MemCached Flea缓存类 </p> * * @param name 缓存主关键字 * @param expiry 失效时长 * @param memCachedClient MemCached客户端 */ public MemCachedFleaCache(String name, long expiry, MemCachedClient memCachedClient) { super(name, expiry); this.memCachedClient = memCachedClient; cache = CacheEnum.MemCached; } @Override public Object getNativeValue(String key) { return memCachedClient.get(key); } @Override public void putNativeValue(String key, Object value, long expiry) { memCachedClient.set(key, value, new Date(expiry * 1000)); } @Override public void deleteNativeValue(String key) { memCachedClient.delete(key); } @Override public String getSystemName() { return MemCachedConfig.getConfig().getSystemName(); } }
到这一步为止,底层的Flea缓存接口和实现已经完成,但目前还不能使用;服务器
/** * <p> MemCached链接池 </p> * * @author huazie */ public class MemCachedPool { private String poolName; // 链接池名 private MemCachedConfig memCachedConfig; // MemCached 配置信息 private SockIOPool sockIOPool; // MemCached SockIOPool private MemCachedPool() { } /** * <p> 获取MemCached链接池实例 (默认) </p> * * @return MemCached链接池实例对象 * @since 1.0.0 */ public static MemCachedPool getInstance() { MemCachedPool memCachedPool = new MemCachedPool(); memCachedPool.memCachedConfig = MemCachedConfig.getConfig(); memCachedPool.sockIOPool = SockIOPool.getInstance(); return memCachedPool; } /** * <p> 获取MemCached链接池实例(指定链接池名poolName) </p> * * @param poolName 链接池名 * @return MemCached链接池实例对象 * @since 1.0.0 */ public static MemCachedPool getInstance(String poolName) { MemCachedPool memCachedPool = new MemCachedPool(); memCachedPool.poolName = poolName; memCachedPool.sockIOPool = SockIOPool.getInstance(poolName); return memCachedPool; } /** * <p> 初始化MemCached链接池 </p> */ void initialize() { if (ObjectUtils.isEmpty(memCachedConfig)) { throw new RuntimeException("采用默认初始化,请使用MemCachedPool##getInstance()"); } // ...省略 sockIOPool 初始化代码 } /** * <p> 初始化MemCached链接池 </p> * * @param cacheServerList 缓存服务器集 * @param cacheParams 缓存参数集 */ void initialize(List<CacheServer> cacheServerList, CacheParams cacheParams) { if (StringUtils.isBlank(poolName)) { throw new RuntimeException("采用指定链接池名初始化,请使用MemCachedPool##getInstance(String poolName)"); } // ...省略 sockIOPool 初始化代码 } // ...省略get方法 }
flea-frame-cache 读取 memcached.properties(Memcached配置文件),用做初始化MemCachedPoolapp
# Memcached配置 # Memcached缓存所属系统名 memcached.systemName=FleaFrame # Memcached服务器地址 memcached.server=127.0.0.1:31113,127.0.0.1:31114 # Memcached服务器权重分配 memcached.weight=1,1 # 初始化时对每一个服务器创建的链接数目 memcached.initConn=20 # 每一个服务器创建最小的链接数 memcached.minConn=20 # 每一个服务器创建最大的链接数 memcached.maxConn=500 # 自查线程周期进行工做,其每次休眠时间 memcached.maintSleep=60000 # Socket的参数,若是是true在写数据时不缓冲,当即发送出去 memcached.nagle=true # Socket阻塞读取数据的超时时间 memcached.socketTO=3000 # Socket链接超时时间 memcached.socketConnectTO=3000 # Memcached分布式hash算法 # 0 - native String.hashCode(); # 1 - original compatibility # 2 - new CRC32 based # 3 - MD5 Based memcached.hashingAlg=3
/** * <p> 自定义抽象缓存管理类 </p> * * @author huazie */ public abstract class AbstractFleaCacheManager { private static final ConcurrentMap<String, AbstractFleaCache> cacheMap = new ConcurrentHashMap<>(); private Map<String, Long> configMap = new HashMap<>(); // 各缓存的时间Map /** * <p> 获取全部的Flea缓存 </p> * * @return 全部的Flea缓存 */ protected Collection<? extends AbstractFleaCache> loadCaches() { return cacheMap.values(); } /** * <p> 根据指定缓存名获取缓存对象 </p> * * @param name 缓存名 * @return 缓存对象 */ public AbstractFleaCache getCache(String name) { if (!cacheMap.containsKey(name)) { synchronized (cacheMap) { if (!cacheMap.containsKey(name)) { Long expiry = configMap.get(name); if (ObjectUtils.isEmpty(expiry)) { expiry = CommonConstants.NumeralConstants.ZERO; // 表示永久 configMap.put(name, expiry); } cacheMap.put(name, newCache(name, expiry)); } } } return cacheMap.get(name); } /** * <p> 新建立一个缓存对象 </p> * * @param name 缓存名 * @param expiry 失效时间(单位:秒 其中0:表示永久) * @return 新建的缓存对象 */ protected abstract AbstractFleaCache newCache(String name, long expiry); /** * <p> 设置各缓存失效时间配置Map </p> * * @param configMap 失效时间配置Map */ public void setConfigMap(Map<String, Long> configMap) { this.configMap = configMap; } }
上述 MemCachedFleaCache 使用, 须要初始化 MemCachedPoolsocket
/** * <p> MemCached Flea缓存管理类 </p> * * @author huazie */ public class MemCachedFleaCacheManager extends AbstractFleaCacheManager { private MemCachedClient memCachedClient; // MemCached客户端类 /** * <p> 新建一个MemCached Flea缓存管理类 </p> */ public MemCachedFleaCacheManager() { memCachedClient = new MemCachedClient(); initPool(); } /** * <p> 新建一个MemCached Flea缓存管理类 </p> * * @param memCachedClient MemCached客户端 */ public MemCachedFleaCacheManager(MemCachedClient memCachedClient) { this.memCachedClient = memCachedClient; initPool(); } /** * <p> 初始化MemCached链接池 </p> */ private void initPool() { MemCachedPool.getInstance().initialize(); } @Override protected AbstractFleaCache newCache(String name, long expiry) { return new MemCachedFleaCache(name, expiry, memCachedClient); } }
好了,到了这一步,Memcached已接入完成,开始自测
首先,这里须要按照 Memcached配置文件中的地址部署相应的 Memcached服务,可参考笔者的 这篇博文。
下面开始演示咱们的Memcached接入自测:
@Test public void testMemeCachedFleaCache() { try { AbstractFleaCacheManager manager = FleaCacheManagerFactory.getFleaCacheManager(CacheEnum.MemCached.getName()); AbstractFleaCache cache = manager.getCache("fleaparadetail"); LOGGER.debug("Cache={}", cache); //#### 1. 简单字符串 // cache.put("menu1", "huazie"); // cache.get("menu1"); cache.delete("menu1"); // cache.getCacheKey(); LOGGER.debug(cache.getCacheName() + ">>>" + cache.getCacheDesc()); } catch (Exception e) { LOGGER.error("Exception:", e); } }
该类与 AbstractFleaCache 不一样之处在于,实现了 Spring 的 Cache 接口,用于对接 Spring,相关配置后面会介绍一下。
/** * <p> 抽象Spring缓存类,实现Spring的Cache 和 自定义的 IFleaCache接口 </p> * * @author huazie */ public abstract class AbstractSpringCache implements Cache, IFleaCache { private final String name; // 缓存主要关键字(用于区分) private final IFleaCache fleaCache; // 具体Flea缓存实现 public AbstractSpringCache(String name, IFleaCache fleaCache) { this.name = name; this.fleaCache = fleaCache; } @Override public String getName() { return name; } @Override public IFleaCache getNativeCache() { return fleaCache; } @Override public ValueWrapper get(Object key) { if (ObjectUtils.isEmpty(key)) return null; ValueWrapper wrapper = null; Object cacheValue = get(key.toString()); if (ObjectUtils.isNotEmpty(cacheValue)) { wrapper = new SimpleValueWrapper(cacheValue); } return wrapper; } @Override @SuppressWarnings(value = "unchecked") public <T> T get(Object key, Class<T> type) { if (ObjectUtils.isEmpty(key)) return null; Object cacheValue = get(key.toString()); if (ObjectUtils.isNotEmpty(type) && !type.isInstance(cacheValue)) { return null; } return (T) cacheValue; } @Override public <T> T get(Object key, Callable<T> valueLoader) { return null; } @Override public Object get(String key) { if (StringUtils.isBlank(key)) return null; Object cacheValue = fleaCache.get(key); return cacheValue; } @Override public void put(Object key, Object value) { if (ObjectUtils.isEmpty(key)) return; put(key.toString(), value); } @Override public ValueWrapper putIfAbsent(Object key, Object value) { if (ObjectUtils.isEmpty(key)) return null; ValueWrapper wrapper = null; Object cacheValue = get(key.toString()); if (ObjectUtils.isEmpty(cacheValue)) { put(key.toString(), value); } else { wrapper = new SimpleValueWrapper(cacheValue); } return wrapper; } @Override public void put(String key, Object value) { fleaCache.put(key, value); } @Override public void evict(Object key) { if (ObjectUtils.isEmpty(key)) return; delete(key.toString()); } @Override public void clear() { fleaCache.clear(); } @Override public void delete(String key) { fleaCache.delete(key); } @Override public Set<String> getCacheKey() { return fleaCache.getCacheKey(); } @Override public String getSystemName() { return fleaCache.getSystemName(); } }
MemCachedSpringCache 只定义构造方法,使用 MemCachedFleaCache 做为具体缓存实现。
/** * <p> MemCached Spring Cache的实现(实现spring的Cache接口)</p> * * @author huazie */ public class MemCachedSpringCache extends AbstractSpringCache { /** * <p> 带参数的构造方法,初始化MemCached Spring缓存类 </p> * * @param name 缓存主关键字 * @param fleaCache 具体缓存实现 */ public MemCachedSpringCache(String name, IFleaCache fleaCache) { super(name, fleaCache); } /** * <p> 带参数的构造方法,初始化MemCached Spring缓存类 </p> * * @param name 缓存主关键字 * @param expiry 失效时长 * @param memCachedClient MemCached客户端 */ public MemCachedSpringCache(String name, long expiry, MemCachedClient memCachedClient) { this(name, new MemCachedFleaCache(name, expiry, memCachedClient)); } }
该类继承 AbstractTransactionSupportingCacheManager,用于对接 Spring。
/** * <p> 抽象Spring缓存管理类 </p> * * @author huazie */ public abstract class AbstractSpringCacheManager extends AbstractTransactionSupportingCacheManager { private static final ConcurrentMap<String, AbstractSpringCache> cacheMap = new ConcurrentHashMap<String, AbstractSpringCache>(); private Map<String, Long> configMap = new HashMap<String, Long>(); // 各缓存的时间Map @Override protected Collection<? extends AbstractSpringCache> loadCaches() { return cacheMap.values(); } @Override public AbstractSpringCache getCache(String name) { if(!cacheMap.containsKey(name)) { synchronized (cacheMap) { if (!cacheMap.containsKey(name)) { Long expiry = configMap.get(name); if (expiry == null) { expiry = CommonConstants.NumeralConstants.ZERO; // 表示永久 configMap.put(name, expiry); } cacheMap.put(name, newCache(name, expiry)); } } } return cacheMap.get(name); } /** * <p> 新建立一个缓存对象 </p> * * @param name 缓存名 * @param expiry 失效时间(单位:秒 其中0:表示永久) * @return 新建的缓存对象 */ protected abstract AbstractSpringCache newCache(String name, long expiry); /** * <p> 设置各缓存失效时间配置Map </p> * * @param configMap 失效时间配置Map */ public void setConfigMap(Map<String, Long> configMap) { this.configMap = configMap; } }
该类基本实现同 MemCachedFleaCacheManager,不一样在于newCache 方法返回一个 MemCachedSpringCache 的对象
/** * <p> Memcached的Spring缓存管理类 </p> * * @author huazie */ public class MemCachedSpringCacheManager extends AbstractSpringCacheManager { private MemCachedClient memCachedClient; // Memcached客户端类 /** * <p> 新建一个MemCached Spring缓存管理类 </p> */ public MemCachedSpringCacheManager() { memCachedClient = new MemCachedClient(); initPool(); } /** * <p> 新建一个MemCached Spring缓存管理类 </p> * * @param memCachedClient MemCached客户端 */ public MemCachedSpringCacheManager(MemCachedClient memCachedClient) { this.memCachedClient = memCachedClient; initPool(); } /** * <p> 初始化MemCached链接池 </p> */ private void initPool() { MemCachedPool.getInstance().initialize(); } @Override protected AbstractSpringCache newCache(String name, long expiry) { return new MemCachedSpringCache(name, expiry, memCachedClient); } }
<!-- 配置缓存管理MemCachedSpringCacheManager 配置缓存时间 configMap (key缓存对象名称 value缓存过时时间) --> <bean id="memCachedSpringCacheManager" class="com.huazie.frame.cache.memcached.MemCachedSpringCacheManager"> <property name="configMap"> <map> <entry key="fleaparadetail" value="86400"/> </map> </property> </bean> <!-- 开启缓存, 此处定义表示由spring接入来管理缓存访问 --> <cache:annotation-driven cache-manager="memCachedSpringCacheManager" proxy-target-class="true"/>
private ApplicationContext applicationContext; @Before public void init() { applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); LOGGER.debug("ApplicationContext={}", applicationContext); } @Test public void testMemCachedSpringCache() { try { AbstractSpringCacheManager manager = (MemCachedSpringCacheManager) applicationContext.getBean("memCachedSpringCacheManager"); LOGGER.debug("MemCachedCacheManager={}", manager); AbstractSpringCache cache = manager.getCache("fleaparadetail"); LOGGER.debug("Cache={}", cache); Set<String> cacheKey = cache.getCacheKey(); LOGGER.debug("CacheKey = {}", cacheKey); // 缓存清理 // cache.clear(); //#### 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)); //#### 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 的接入工做已经所有完成,下一篇将讲解 flea-frame-cache使用之Redis接入,敬请期待哦!!!