Memcached接入

1. 参考

flea-cache使用之Memcached接入 源代码

2. 依赖

Memcached-Java-Client-3.0.2.jar

<!-- Memcached相关 -->
<dependency><groupId>com.whalin</groupId><artifactId>Memcached-Java-Client</artifactId><version>3.0.2</version>
</dependency>

spring-context-4.3.18.RELEASE.jar

<!-- 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>

3. 基础接入

3.1 定义Flea缓存接口 — IFleaCache

/*** <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();
}

3.2 定义抽象Flea缓存类 — AbstractFleaCache

/*** 抽象Flea Cache类,实现了Flea缓存接口的读、写、删除和清空缓存的基本操作。** <p> 它定义本地读、本地写和本地删除的抽象方法,由子类实现具体的读、* 写和删除缓存的操作。** <p> 在实际调用写缓存操作时,会同时记录当前缓存数据的数据键关键字* 【{@code key}】到专门的数据键关键字的缓存中,以Set集合存储。** <p> 比如缓存数据主关键字为【{@code name}】,需要存储的数据键关键字为* 【{@code key}】,则在实际调用写缓存操作时,会操作两条缓存数据:<br/>* 一条是具体的数据缓存,缓存键为“系统名_name_key”,可查看方法* 【{@code getNativeKey}】,有效期从配置中获取;<br/>* 一条是数据键关键字的缓存,缓存键为“系统名_name”,可查看方法* 【{@code getNativeCacheKey}】,默认永久有效。** @author huazie* @version 1.1.0* @since 1.0.0*/
public abstract class AbstractFleaCache implements IFleaCache {private static final FleaLogger LOGGER = FleaLoggerProxy.getProxyInstance(AbstractFleaCache.class);private final String name;  // 缓存数据主关键字private final int expiry;  // 缓存数据有效期(单位:s)private final int nullCacheExpiry; // 空缓存数据有效期(单位:s)protected CacheEnum cache;  // 缓存实现public AbstractFleaCache(String name, int expiry, int nullCacheExpiry) {this.name = name;this.expiry = expiry;this.nullCacheExpiry = nullCacheExpiry;}@Overridepublic Object get(String key) {Object value = null;try {value = getNativeValue(getNativeKey(key));if (value instanceof NullCache) {value = null;}} catch (Exception e) {if (LOGGER.isErrorEnabled()) {LOGGER.error1(new Object() {}, "The action of getting [" + cache.getName() + "] cache occurs exception : ", e);}}return value;}@Overridepublic void put(String key, Object value) {try {putNativeValue(getNativeKey(key), value, expiry);// 将指定Cache的key添加到Set集合,并存于缓存中addCacheKey(key);} catch (Exception e) {if (LOGGER.isErrorEnabled()) {LOGGER.error1(new Object() {}, "The action of adding [" + cache.getName() + "] cache occurs exception : ", e);}}}@Overridepublic void clear() {Set<String> keySet = getCacheKey();if (CollectionUtils.isNotEmpty(keySet)) {for (String key : keySet) {deleteNativeValue(getNativeKey(key));}// 删除 记录当前Cache所有数据键关键字 的缓存deleteCacheAllKey();}}@Overridepublic void delete(String key) {try {deleteNativeValue(getNativeKey(key));// 从 记录当前Cache所有数据键关键字 的缓存中 删除指定数据键关键字keydeleteCacheKey(key);} catch (Exception e) {if (LOGGER.isErrorEnabled()) {LOGGER.error1(new Object() {}, "The action of deleting [" + cache.getName() + "] cache occurs exception : ", e);}}}/*** <p> 将指定数据键关键字{@code key}记录到当前Cache所有数据键关键字的缓存中 </p>** @param key 指定Cache的数据键关键字* @since 1.0.0*/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.INT_ZERO);}}/*** <p> 从 记录当前Cache所有数据键关键字 的缓存中 删除指定数据键关键字{@code key} </p>** @param key 指定Cache的数据键关键字* @since 1.0.0*/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.INT_ZERO);}} else {if (LOGGER.isDebugEnabled()) {LOGGER.debug1(new Object() {}, "The CacheKey of [{}] is not exist", key);}}}}/*** <p> 删除 记录当前Cache所有数据键关键字 的缓存 </p>** @since 1.0.0*/private void deleteCacheAllKey() {try {deleteNativeValue(getNativeCacheKey(name));} catch (Exception e) {if (LOGGER.isErrorEnabled()) {LOGGER.error1(new Object() {}, "The action of deleting [" + cache.getName() + "] cache occurs exception : ", e);}}}@Override@SuppressWarnings(value = "unchecked")public Set<String> getCacheKey() {Set<String> keySet = null;try {Object keySetObj = getNativeValue(getNativeCacheKey(name));if (ObjectUtils.isNotEmpty(keySetObj) && keySetObj instanceof Set) {keySet = (Set<String>) keySetObj;}} catch (Exception e) {if (LOGGER.isErrorEnabled()) {LOGGER.error1(new Object() {}, "The action of getting [" + cache.getName() + "] cache occurs exception : ", e);}}return keySet;}/*** <p> 获取缓存值 </p>** @param key 缓存数据键关键字* @return 缓存值* @since 1.0.0*/public abstract Object getNativeValue(String key);/*** <p> 添加缓存数据 </p>** @param key    缓存数据键关键字* @param value  缓存值* @param expiry 有效期(单位:s)* @since 1.0.0*/public abstract Object putNativeValue(String key, Object value, int expiry);/*** <p> 删除指定缓存数据 </p>** @param key 缓存数据键关键字* @since 1.0.0*/public abstract Object deleteNativeValue(String key);/*** <p> 获取实际存储的缓存键【缓存所属系统名 + 缓存名(缓存数据主关键字)+ 缓存数据键(缓存数据关键字)】 </p>** @param key 缓存数据键关键字* @return 实际存储的缓存键* @since 1.0.0*/private String getNativeKey(String key) {return StringUtils.strCat(getNativeCacheKey(name), CommonConstants.SymbolConstants.UNDERLINE, key);}/*** <p> 获取缓存主键【包含缓存所属系统名 + 缓存名(缓存数据主关键字)】 </p>** @param name 缓存名【缓存数据主关键字】* @return 缓存主键【缓存所属系统名 + 缓存名(缓存数据主关键字)】* @since 1.0.0*/protected String getNativeCacheKey(String name) {return StringUtils.strCat(getSystemName(), CommonConstants.SymbolConstants.UNDERLINE, name);}// 省略一些get方法
}

该类实现了IFleaCache接口,同时定义了三个抽象方法 :

    public abstract Object getNativeValue(String key);public abstract void putNativeValue(String key, Object value, int expiry);public abstract void deleteNativeValue(String key);

这三个抽象方法由子类实现具体的读,写,删除缓存的原始操作

3.3 定义MemCached Flea缓存类 — MemCachedFleaCache

该类继承 AbstractFleaCache,实现Memcached缓存的接入使用;

/*** MemCached Flea缓存类,实现了以Flea框架操作MemCached缓存的基本操作方法。** <p> 在上述基本操作方法中,实际使用MemCached客户端【{@code} memCachedClient】* 读、写和删除MemCached缓存。其中写缓存方法【{@code putNativeValue}】在* 添加的数据值为【{@code null}】时,默认添加空缓存数据【{@code NullCache}】* 到MemCached中,有效期取初始化参数【{@code nullCacheExpiry}】。** <p> 单个缓存接入场景,有效期配置可查看【memcached.properties】中的配置* 参数【memcached.nullCacheExpiry】** <p> 整合缓存接入场景,有效期配置可查看【flea-cache-config.xml】* 中的缓存参数【{@code <cache-param key="fleacore.nullCacheExpiry"* desc="空缓存数据有效期(单位:s)">300</cache-param>}】** @author huazie* @version 1.0.0* @since 1.0.0*/
public class MemCachedFleaCache extends AbstractFleaCache {private final MemCachedClient memCachedClient;  // MemCached客户端/*** <p> 初始化MemCached Flea缓存类 </p>** @param name            缓存数据主关键字* @param expiry          缓存数据有效期(单位:s)* @param nullCacheExpiry 空缓存数据有效期(单位:s)* @param memCachedClient MemCached客户端* @since 1.0.0*/public MemCachedFleaCache(String name, int expiry, int nullCacheExpiry, MemCachedClient memCachedClient) {super(name, expiry, nullCacheExpiry);this.memCachedClient = memCachedClient;cache = CacheEnum.MemCached;}@Overridepublic Object getNativeValue(String key) {if (LOGGER.isDebugEnabled()) {LOGGER.debug1(new Object() {}, "KEY = {}", key);}return memCachedClient.get(key);}@Overridepublic Object putNativeValue(String key, Object value, int expiry) {if (ObjectUtils.isEmpty(value))return memCachedClient.set(key, new NullCache(key), new Date(getNullCacheExpiry() * 1000));elsereturn memCachedClient.set(key, value, new Date(expiry * 1000));}@Overridepublic Object deleteNativeValue(String key) {return memCachedClient.delete(key);}@Overridepublic String getSystemName() {return MemCachedConfig.getConfig().getSystemName();}
}

到这一步为止,底层的Flea缓存接口和实现已经完成,但目前还不能使用;

3.4 定义Memcached连接池 — MemCachedPool

/*** Flea MemCached连接池,用于初始化MemCached的套接字连接池。** <p> 针对单独缓存接入场景,采用默认连接池初始化的方式;<br/>* 可参考如下:* <pre>*   // 初始化默认连接池*   MemCachedPool.getInstance().initialize(); </pre>** <p> 针对整合缓存接入场景,采用指定连接池初始化的方式;<br/>* 可参考如下:* <pre>*   // 初始化指定连接池*   MemCachedPool.getInstance(group).initialize(cacheServerList); </pre>** @author huazie* @version 1.1.0* @since 1.0.0*/
public class MemCachedPool {private String poolName; // 连接池名private MemCachedConfig memCachedConfig; // MemCached 配置信息private SockIOPool sockIOPool; // MemCached SockIOPoolprivate 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>** @since 1.0.0*/public void initialize() {// 省略。。。。。。}/*** <p> 初始化MemCached连接池 </p>** @param cacheServerList 缓存服务器集* @since 1.0.0*/public void initialize(List<CacheServer> cacheServerList) {// 省略。。。。。。}// 详见 GitHub 链接
}

3.5 Memcached配置文件

flea-cache 读取 memcached.properties(Memcached配置文件),用作初始化 MemCachedPool

# 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# 自查线程周期进行工作,其每次休眠时间(单位:ms)
memcached.maintSleep=60000# Socket的参数,如果是true在写数据时不缓冲,立即发送出去
memcached.nagle=true# Socket阻塞读取数据的超时时间(单位:ms)
memcached.socketTO=3000# Socket连接超时时间(单位:ms)
memcached.socketConnectTO=3000# 空缓存数据有效期(单位:s)
memcached.nullCacheExpiry=10# Memcached分布式hash算法
# 0 - native String.hashCode();
# 1 - original compatibility
# 2 - new CRC32 based
# 3 - MD5 Based
memcached.hashingAlg=3

3.6 定义抽象Flea缓存管理类 — AbstractFleaCacheManager

/*** 抽象Flea缓存管理类,用于接入Flea框架管理缓存。** <p> 同步集合类【{@code cacheMap}】, 存储的键为缓存数据主关键字,* 存储的值为具体的缓存实现类。<br/>* 如果是整合各类缓存接入,它的键对应缓存定义配置文件【flea-cache.xml】* 中的【{@code <cache key="缓存数据主关键字"></cache>}】;<br/>* 如果是单个缓存接入,它的键对应【applicationContext.xml】中* 【{@code <entry key="缓存数据主关键字"value="有效期(单位:s)"/>}】;** <p> 抽象方法【{@code newCache}】,由子类实现具体的Flea缓存类创建。** @author huazie* @version 1.0.0* @since 1.0.0*/
public abstract class AbstractFleaCacheManager {private static final ConcurrentMap<String, AbstractFleaCache> cacheMap = new ConcurrentHashMap<>();private Map<String, Integer> configMap = new HashMap<>();   // 各缓存的时间Map/*** <p> 获取所有的Flea缓存 </p>** @return 所有的Flea缓存* @since 1.0.0*/protected Collection<AbstractFleaCache> loadCaches() {return cacheMap.values();}/*** <p> 根据指定缓存名获取缓存对象 </p>** @param name 缓存名* @return 缓存对象* @since 1.0.0*/public AbstractFleaCache getCache(String name) {if (!cacheMap.containsKey(name)) {synchronized (cacheMap) {if (!cacheMap.containsKey(name)) {Integer expiry = configMap.get(name);if (ObjectUtils.isEmpty(expiry)) {expiry = CommonConstants.NumeralConstants.INT_ZERO; // 表示永久configMap.put(name, expiry);}cacheMap.put(name, newCache(name, expiry));}}}return cacheMap.get(name);}/*** <p> 新创建一个缓存对象 </p>** @param name   缓存名* @param expiry 有效期(单位:s  其中0:表示永久)* @return 新建的缓存对象* @since 1.0.0*/protected abstract AbstractFleaCache newCache(String name, int expiry);/*** <p> 设置各缓存有效期配置Map </p>** @param configMap 有效期配置Map* @since 1.0.0*/public void setConfigMap(Map<String, Integer> configMap) {this.configMap = configMap;}}

3.7 定义Memcached Flea缓存管理类 MemCachedFleaCacheManager

上述 MemCachedFleaCache 使用, 需要初始化 MemCachedPool

/*** MemCached Flea缓存管理类,用于接入Flea框架管理MemCached 缓存。** <p> 它的默认构造方法,用于单个缓存接入场景,首先新建MemCached客户端,* 然后初始化 MemCached 连接池。** <p> 方法 {@code newCache},用于创建一个MemCached Flea缓存,* 它里面包含了 读、写、删除 和 清空 缓存的基本操作。** @author huazie* @version 1.0.0* @see MemCachedFleaCache* @since 1.0.0*/
public class MemCachedFleaCacheManager extends AbstractFleaCacheManager {private MemCachedClient memCachedClient;   // MemCached客户端类/*** 用于新建MemCached客户端,并初始化MemCached连接池。** @since 1.0.0*/public MemCachedFleaCacheManager() {memCachedClient = new MemCachedClient();initPool();}/*** 以传入参数初始化MemCached客户端,并初始化MemCached连接池。** @param memCachedClient MemCached客户端* @since 1.0.0*/public MemCachedFleaCacheManager(MemCachedClient memCachedClient) {this.memCachedClient = memCachedClient;initPool();}/*** <p> 初始化MemCached连接池 </p>** @since 1.0.0*/private void initPool() {MemCachedPool.getInstance().initialize();}@Overrideprotected AbstractFleaCache newCache(String name, int expiry) {int nullCacheExpiry = MemCachedConfig.getConfig().getNullCacheExpiry();return new MemCachedFleaCache(name, expiry, nullCacheExpiry, memCachedClient);}
}

好了,到了这一步,Memcached已接入完成,开始自测

3.8 Memcached接入自测 — FleaCacheTest

首先,这里需要按照 Memcached配置文件中的地址部署相应的 Memcached服务,可参考笔者的 这篇博文。

下面开始演示我们的Memcached接入自测:

    @Testpublic 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);}}

4. 进阶接入

4.1 定义抽象Spring缓存 — AbstractSpringCache

该类与 AbstractFleaCache 不同之处在于,实现了 SpringCache 接口,用于对接 Spring,相关配置后面会介绍一下。

/*** 抽象 Spring 缓存类,实现Spring的Cache接口 和 Flea* 的IFleaCache接口,由具体的Spring缓存管理类初始化。** <p> 它实现了读、写、删除和清空缓存的基本操作方法,* 内部由具体Flea缓存实现类【{@code fleaCache}】* 调用对应的 读、写、删除 和 清空 缓存的基本操作方法。** @author huazie* @version 1.1.0* @since 1.0.0*/
public abstract class AbstractSpringCache implements Cache, IFleaCache {private static final FleaLogger LOGGER = FleaLoggerProxy.getProxyInstance(AbstractSpringCache.class);private final String name;  // 缓存主要关键字(用于区分)private final IFleaCache fleaCache; // 具体Flea缓存实现public AbstractSpringCache(String name, IFleaCache fleaCache) {this.name = name;this.fleaCache = fleaCache;}@Overridepublic String getName() {return name;}@Overridepublic IFleaCache getNativeCache() {return fleaCache;}@Overridepublic 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;}@Overridepublic <T> T get(Object key, Class<T> type) {if (ObjectUtils.isEmpty(key) || ObjectUtils.isEmpty(type))return null;Object cacheValue = get(key.toString());if (!type.isInstance(cacheValue)) {if (LOGGER.isDebugEnabled()) {LOGGER.debug1(new Object() {}, "Cached value is not of required type [{}] : {}", type.getName(), cacheValue);}return null;}return type.cast(cacheValue);}@Overridepublic <T> T get(Object key, Callable<T> valueLoader) {return null;}@Overridepublic Object get(String key) {if (StringUtils.isBlank(key))return null;Object obj = null;if (LOGGER.isDebugEnabled()) {obj = new Object() {};LOGGER.debug1(obj, "KEY = {}", key);}Object cacheValue = fleaCache.get(key);if (LOGGER.isDebugEnabled()) {LOGGER.debug1(obj, "VALUE = {}", cacheValue);}return cacheValue;}@Overridepublic void put(Object key, Object value) {if (ObjectUtils.isEmpty(key))return;put(key.toString(), value);}@Overridepublic 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;}@Overridepublic void put(String key, Object value) {fleaCache.put(key, value);}@Overridepublic void evict(Object key) {if (ObjectUtils.isEmpty(key))return;delete(key.toString());}@Overridepublic void clear() {fleaCache.clear();}@Overridepublic void delete(String key) {fleaCache.delete(key);}@Overridepublic Set<String> getCacheKey() {return fleaCache.getCacheKey();}@Overridepublic String getSystemName() {return fleaCache.getSystemName();}
}

4.2 定义Memcached Spring缓存 — MemCachedSpringCache

MemCachedSpringCache 只定义构造方法,使用 MemCachedFleaCache 作为具体缓存实现。

/*** MemCached Spring缓存类,继承了抽象Spring缓存父类的* 读、写、删除 和 清空 缓存的基本操作方法,由MemCached Spring缓存管理类初始化。** <p> 它的构造方法中,必须传入一个具体Flea缓存实现类,这里我们使用* MemCached Flea缓存【{@code MemCachedFleaCache}】。** @author huazie* @version 1.0.0* @see MemCachedFleaCache* @since 1.0.0*/
public class MemCachedSpringCache extends AbstractSpringCache {/*** <p> 带参数的构造方法,初始化MemCached Spring缓存类 </p>** @param name      缓存数据主关键字* @param fleaCache 具体缓存实现* @since 1.0.0*/public MemCachedSpringCache(String name, IFleaCache fleaCache) {super(name, fleaCache);}/*** <p> 带参数的构造方法,初始化MemCached Spring缓存类 </p>** @param name            缓存数据主关键字* @param expiry          缓存数据有效期(单位:s)* @param nullCacheExpiry 空缓存数据有效期(单位:s)* @param memCachedClient MemCached客户端* @since 1.0.0*/public MemCachedSpringCache(String name, int expiry, int nullCacheExpiry, MemCachedClient memCachedClient) {this(name, new MemCachedFleaCache(name, expiry, nullCacheExpiry, memCachedClient));}
}

4.3 定义抽象Spring缓存管理类 — AbstractSpringCacheManager

该类继承 AbstractTransactionSupportingCacheManager,用于对接 Spring

/*** 抽象Spring缓存管理类,用于接入Spring框架管理缓存。** <p> 同步集合类【{@code cacheMap}】, 存储的键为缓存数据主关键字,* 存储的值为具体的缓存实现类。<br/>* 如果是整合各类缓存接入,它的键对应缓存定义配置文件【flea-cache.xml】* 中的【{@code <cache key="缓存数据主关键字"></cache>}】;<br/>* 如果是单个缓存接入,它的键对应【applicationContext.xml】中* 【{@code <entry key="缓存数据主关键字" value="有效期(单位:s)"/>}】;** <p> 抽象方法【{@code newCache}】,由子类实现具体的Spring缓存类创建。** @author huazie* @version 1.0.0* @since 1.0.0*/
public abstract class AbstractSpringCacheManager extends AbstractTransactionSupportingCacheManager {private static final ConcurrentMap<String, AbstractSpringCache> cacheMap = new ConcurrentHashMap<>();private Map<String, Integer> configMap = new HashMap<>();   // 各缓存的时间Map@Overrideprotected Collection<? extends AbstractSpringCache> loadCaches() {return cacheMap.values();}@Overridepublic AbstractSpringCache getCache(String name) {if (!cacheMap.containsKey(name)) {synchronized (cacheMap) {if (!cacheMap.containsKey(name)) {Integer expiry = configMap.get(name);if (expiry == null) {expiry = CommonConstants.NumeralConstants.INT_ZERO; // 表示永久configMap.put(name, expiry);}cacheMap.put(name, newCache(name, expiry));}}}return cacheMap.get(name);}/*** 由子类实现该方法,新创建一个抽象 Spring 缓存的子类。** @param name   缓存名* @param expiry 有效期(单位:s  其中0:表示永久)* @return 新建的缓存对象* @since 1.0.0*/protected abstract AbstractSpringCache newCache(String name, int expiry);/*** <p> 设置各缓存有效期配置Map </p>** @param configMap 有效期配置Map* @since 1.0.0*/public void setConfigMap(Map<String, Integer> configMap) {this.configMap = configMap;}
}

4.4 定义Memcached Spring缓存管理类 — MemCachedSpringCacheManager

该类基本实现同 MemCachedFleaCacheManager,不同在于newCache 方法返回一个 MemCachedSpringCache 的对象

/*** MemCached Spring缓存管理类,用于接入Spring框架管理 MemCached 缓存。** <p> 它的默认构造方法,用于单个缓存接入场景,首先新建MemCached 客户端,* 然后初始化 MemCached 连接池。** <p> 方法【{@code newCache}】用于创建一个MemCached Spring缓存,* 而它内部是由MemCached Flea缓存实现具体的 读、写、删除 和 清空* 缓存的基本操作。** @author huazie* @version 1.0.0* @see MemCachedSpringCache* @since 1.0.0*/
public class MemCachedSpringCacheManager extends AbstractSpringCacheManager {private MemCachedClient memCachedClient;   // MemCached客户端类/*** 用于新建MemCached客户端,并初始化MemCached连接池。** @since 1.0.0*/public MemCachedSpringCacheManager() {memCachedClient = new MemCachedClient();initPool();}/*** 以传入参数初始化MemCached客户端,并初始化MemCached连接池。** @param memCachedClient MemCached客户端*/public MemCachedSpringCacheManager(MemCachedClient memCachedClient) {this.memCachedClient = memCachedClient;initPool();}/*** <p> 初始化MemCached连接池 </p>** @since 1.0.0*/private void initPool() {MemCachedPool.getInstance().initialize();}@Overrideprotected AbstractSpringCache newCache(String name, int expiry) {int nullCacheExpiry = MemCachedConfig.getConfig().getNullCacheExpiry();return new MemCachedSpringCache(name, expiry, nullCacheExpiry, memCachedClient);}
}

4.5 spring 配置

<!--配置缓存管理MemCachedSpringCacheManager配置缓存时间 configMap (key缓存对象名称 value缓存过期时间)
-->
<bean id="memCachedSpringCacheManager" class="com.huazie.fleaframework.cache.memcached.manager.MemCachedSpringCacheManager"><property name="configMap"><map><entry key="fleaparadetail" value="86400"/></map></property>
</bean><!-- 开启缓存, 此处定义表示由spring接入来管理缓存访问 --><cache:annotation-driven cache-manager="memCachedSpringCacheManager" proxy-target-class="true"/>

4.6 缓存自测

    private ApplicationContext applicationContext;@Beforepublic void init() {applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");LOGGER.debug("ApplicationContext={}", applicationContext);}@Testpublic 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);}}

4.7 业务逻辑层接入缓存管理

@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-cache使用之Redis分片模式接入,敬请期待哦!!!

flea-cache使用之Memcached接入相关推荐

  1. php安装mem+cache扩展,安装memcached及php扩展

    用的是centos系统 1.安装memcached yum -y install memcached 安装完成后, memcached -h 应该会出现memcached 参数说明 2.memcach ...

  2. python cache MySQL_Python判断Memcached是否缓存MySQL结果

    介绍一个生产环境中memcached的使用场景,主要是memcached存储关系型数据库MySQL的查询结果,比如网站的下载排名等,这种查询每次从关系型数据库中查询,会增加磁盘的I/O开销,而这个排名 ...

  3. flea-cache使用之Redis分片模式接入

    Redis分片模式接入 1. 参考 flea-cache使用之Redis分片模式接入 源代码 2. 依赖 jedis-3.0.1.jar <!-- Java redis --> <d ...

  4. memcached的最佳实践方案(转)

    基本问题 1.memcached的基本设置  1)启动Memcache的服务器端  # /usr/local/bin/memcached -d -m 10 -u root -l 192.168.0.2 ...

  5. memcached企业面试题

    面试题如下: 1.Memcached是什么,有什么作用? Memcached是一个开源的,高性能的内存绶存软件,从名称上看Mem就是内存的意思,而Cache就是缓存的意思. Memcached的作用: ...

  6. Go实战--也许最快的Go语言Web框架kataras/iris初识二(TOML、Cache、Cookie)

    生命不止,继续 go go go!!! 昨天介绍了iris框架,介绍了如何使用basic认证.Markdown.YAML.Json等:  Go实战–也许最快的Go语言Web框架kataras/iris ...

  7. CentOS6.8下安装memcached并设置开机自启动

    参考资料:http://www.cnblogs.com/handongyu/p/6419305.html    http://coolnull.com/1986.html 一.安装libevent 首 ...

  8. Memcached 内存管理(一)

    2019独角兽企业重金招聘Python工程师标准>>> Memcached是一个高效的分布式内存cache,了解memcached的内存管理机制,便于我们理解memcached,让我 ...

  9. Memcached服务端自动启动(转载)

    Memcached服务端自动启动 原文链接:http://www.cnblogs.com/technet/archive/2011/09/11/2173485.html  经测试,要使得Memcach ...

  10. memcached 内存管理 分析(转)

    Memcached是一个高效的分布式内存cache,了解memcached的内存管理机制,便于我们理解memcached,让我们可以针对我们数据特点进行调优,让其更好的为我所用.这里简单谈一下我对me ...

最新文章

  1. 查询语句索引不能使用的一些情况
  2. './mysql-bin.index' not found (Errcode: 13) 的解决方法
  3. mysql注册slave_创建slave库?spm=a2c4e.11155472的搜索结果-阿里云开发者社区
  4. date_default_timezone_set()问题解决方案(PHP5.3以上的)
  5. Net::SSH::Perl 包 与 Net::OpenSSH 包的 性能对比代码
  6. 史上最便捷搭建 Zookeeper 的方法!
  7. Paper Read: Robust Deep Multi-modal Learning Based on Gated Information Fusion Network
  8. iometer使用教程linux,Iometer磁盘测试工具中文使用说明手册 二
  9. 毕业论文Word排版专题
  10. 有源滤波器设计工具枪战---凯利讯半导体
  11. JJ斗地主记牌器java开发,【欢乐斗地主记牌器制作】遇到两个问题
  12. kindle可以看html格式文章吗,Kindle 新功能上线:终于可以显示阅读数据了
  13. oppoA83怎么升级android版本,OPPOA83系统刷机包(官方最新固件升级包正式版-A.37)...
  14. Delphi修改FMX Label字体颜色
  15. 恒生电子:主推2条联盟链,但链上交易至今不到30笔 |追击上市公司
  16. 灵魂碎片的收集(构造)
  17. 教大家如何清理C盘~
  18. 台积电2016年6月营收公布:股价飙升创台个股新记录
  19. 静态页面 常见问题 margin-top塌陷、padding把盒子撑大
  20. 《统计学习方法》全部算法

热门文章

  1. action = “store_true
  2. 读取采购订单附件(GOS)-[BDS_GOS_CONNECTIONS_GET/SO_DOCUMENT_READ_API1]
  3. redis的failover ,redmon安装
  4. 安装ruby1.9.3-p0及redmon来监控redis
  5. 远程登陆Win10自带子系统Ubuntu-22.04
  6. 内存泄漏工具asan
  7. android 分辨率 尺寸大小,Andriod界面设计的分辨率和尺寸适配全攻略
  8. eot文件html,html – 为什么IE8没有加载我的eot文件?
  9. SAS 方差分析(复习4)
  10. 如何制作一款Chrome浏览器扩展程序