flea-frame-cache使用之整合Memcached和Redis接入

整合Memcached和Redis接入

参考

flea-frame-cache使用之整合Memcached和Redis接入 源代码

依赖

不再赘述,详见我的如下博文:

flea-frame-cache使用之Memcached接入

flea-frame-cache使用之Redis接入

使用讲解

经过上两篇博文,Memcached和Redis相信很多朋友都能成功的接入系统应用了。随着应用的复杂度上升,缓存的应用场景不断增多,单独的对接一个缓存系统,已经无法满足业务开发要求。本文着眼于整合多套缓存接入:一个缓存 cache 对应一个缓存数据 cache-data,一个缓存数据 cache-data 对应一个缓存组 cache-group,多个缓存服务器 cache-server 关联一个缓存组 cache-group,一个缓存组 cache-group 对应具体的缓存接入实现(目前支持 Memcached 和 Redis)。下面且听我慢慢道来:

1. Flea缓存配置文件 flea-cache-config.xml

<?xml version="1.0" encoding="UTF-8"?>

<flea-cache-config>

    <!-- 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连接池最大连接数">8</cache-param>
        <cache-param key="pool.maxIdle" desc="Redis客户端Jedis连接池最大空闲连接数">8</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="auth" desc="Flea权限缓存数据所在组配置">authGroup</cache-data>
        <cache-data type="jersey" desc="Flea Jersey缓存数据所在组配置">configGroup</cache-data>
        <cache-data type="fleafs" desc="FleaFs配置数据所在组配置">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>

2. Flea缓存定义文件 flea-cache.xml

<?xml version="1.0" encoding="UTF-8"?>

<flea-cache>
	<!-- 缓存定义 -->
    <caches>
        <!-- 
            key : 缓存主关键字,即缓存名 
            type : 缓存类型
            expiry : 缓存失效时长(单位:s),该字段可以配置(默认永久有效)
            desc : 缓存描述
         -->
        <cache key="fleaparadetail" type="fleafs" expiry="86400" desc="Flea配置数据缓存" />
        
        <cache key="fleajerseyi18nerrormapping" type="jersey" desc="Flea Jersey 国际码和错误码映射缓存" />
        <cache key="fleajerseyresservice" type="jersey" desc="Flea Jersey 资源服务缓存" />
        <cache key="fleajerseyresclient" type="jersey" desc="Flea Jersey 资源客户端缓存" />
        <cache key="fleajerseyresource" type="jersey" desc="Flea Jersey 资源缓存" />
    </caches>

</flea-cache>

3. 定义核心Flea缓存类 CoreFleaCache

该类同样继承抽象Flea缓存 AbstractFleaCache,实现其定义的抽象方法;内部定义成员变量fleaCache用于指定具体的Flea缓存实现(这个具体的实现,可参考前面Memcached和Redis接入),实现的三个方法getNativeValueputNativeValuedeleteNativeValue内部采用具体Flea缓存实现fleaCache相应的方法实现读缓存、写缓存,删缓存;从构造方法可见,fleaCache通过 FleaCacheFactory.getFleaCache(name) ,从Flea缓存工厂中获取;

/**
 * <p> 核心Flea缓存类 </p>
 *
 * @author huazie
 * @version 1.0.0
 * @since 1.0.0
 */
public class CoreFleaCache extends AbstractFleaCache {
    
    

    private static final Logger LOGGER = LoggerFactory.getLogger(CoreFleaCache.class);

    private AbstractFleaCache fleaCache; // 指定Flea缓存实现

    /**
     * <p> 带参数构造方法,初始化核心Flea缓存类 </p>
     *
     * @param name 缓存主关键字
     * @since 1.0.0
     */
    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) {
    
    
        if (LOGGER.isDebugEnabled()) {
    
    
            LOGGER.debug("CoreFleaCache##getNativeValue(String) KEY = {}", key);
        }
        return fleaCache.getNativeValue(key);
    }

    @Override
    public void putNativeValue(String key, Object value, long expiry) {
    
    
        if (LOGGER.isDebugEnabled()) {
    
    
            LOGGER.debug("CoreFleaCache##putNativeValue(String, Object, long) KEY = {}", key);
            LOGGER.debug("CoreFleaCache##putNativeValue(String, Object, long) VALUE = {}", value);
            LOGGER.debug("CoreFleaCache##putNativeValue(String, Object, long) EXPIRY = {}s", expiry);
        }
        fleaCache.putNativeValue(key, value, expiry);
    }

    @Override
    public void deleteNativeValue(String key) {
    
    
        if (LOGGER.isDebugEnabled()) {
    
    
            LOGGER.debug("CoreFleaCache##deleteNativeValue(String) KEY = {}", key);
        }
        fleaCache.deleteNativeValue(key);
    }
}

4. 定义Flea缓存工厂类 FleaCacheFactory

该类根据缓存名(即缓存主关键字)所创建的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;
    }

}

5. 定义Flea缓存建造者接口类 IFleaCacheBuilder

/**
 * <p> Flea缓存建造者接口类 </p>
 *
 * @author huazie
 * @version 1.0.0
 * @since 1.0.0
 */
public interface IFleaCacheBuilder {
    
    

    /**
     * <p> 构建Flea缓存对象 </p>
     *
     * @param name            缓存主关键字
     * @param cacheServerList 缓存服务器集
     * @param cacheParams     缓存参数集
     * @return Flea缓存对象
     * @since 1.0.0
     */
    AbstractFleaCache build(String name, List<CacheServer> cacheServerList, CacheParams cacheParams);

}

6. 定义Memcached Flea缓存建造者 MemCachedFleaCacheBuilder

该类实现 IFleaCacheBuilder,用于构建基于Memcached的Flea缓存,即创建一个 MemCachedFleaCache

/**
 * <p> MemCached的Flea缓存建造者实现 </p>
 *
 * @author huazie
 * @version 1.0.0
 * @since 1.0.0
 */
public class MemCachedFleaCacheBuilder implements IFleaCacheBuilder {
    
    

    private static final Logger LOGGER = LoggerFactory.getLogger(MemCachedFleaCacheBuilder.class);

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

        if (LOGGER.isDebugEnabled()) {
    
    
            LOGGER.debug("MemCachedFleaCacheBuilder#build(String, List<CacheServer>, CacheParams) Pool Name = {}", memCachedPool.getPoolName());
            LOGGER.debug("MemCachedFleaCacheBuilder#build(String, List<CacheServer>, CacheParams) Pool = {}", memCachedPool.getSockIOPool());
        }

        return fleaCache;
    }
}

7. 定义Redis Flea缓存建造者 RedisFleaCacheBuilder

该类实现 IFleaCacheBuilder,用于构建基于Redis的Flea缓存,即创建一个 RedisFleaCache

/**
 * <p> Redis的Flea缓存建造者实现 </p>
 *
 * @author huazie
 * @version 1.0.0
 * @since 1.0.0
 */
public class RedisFleaCacheBuilder implements IFleaCacheBuilder {
    
    

    private static final Logger LOGGER = LoggerFactory.getLogger(RedisFleaCacheBuilder.class);

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

        if (LOGGER.isDebugEnabled()) {
    
    
            LOGGER.debug("RedisFleaCacheBuilder#build(String, List<CacheServer>, CacheParams) Pool Name = {}", RedisPool.getInstance(group).getPoolName());
            LOGGER.debug("RedisFleaCacheBuilder#build(String, List<CacheServer>, CacheParams) Pool = {}", RedisPool.getInstance(group).getJedisPool());
        }

        return fleaCache;
    }
}

8. 定义核心Flea缓存管理类 CoreFleaCacheManager

核心Flea缓存 CoreFleaCache 经过上述步骤已经能够投入使用;该类继承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);
    }
}

9. 缓存自测

    @Test
    public void testCoreFleaCacheManager() {
    
    
        try {
    
    
            AbstractFleaCacheManager manager = new CoreFleaCacheManager();
            AbstractFleaCache cache = manager.getCache("fleaparadetail");
            LOGGER.debug("Cache={}", cache);
            //#### 1.  简单字符串
//            cache.put("menu1", "huazie");
//            cache.put("menu2", "helloworld");
//            cache.get("menu1");
//            cache.delete("menu2");
            cache.getCacheKey();
            LOGGER.debug(cache.getCacheName() + ">>>" + cache.getCacheDesc());
        } catch (Exception e) {
    
    
            LOGGER.error("Exception:", e);
        }
    }

经过上面的介绍,核心Flea缓存相关的内容,基本上算是讲解完毕。在不改变现有业务代码的基础上,相关缓存 cache 可以通过修改其归属的缓存数据类型 type,实现各缓存,多套缓存之间的无缝迁移。

进阶练习

1. 定义核心Spring缓存 CoreSpringCache

该类同样继承抽象Spring缓存 AbstractSpringCache,用于对接Spring;从构造方法可见,该类初始化使用核心Flea缓存类 CoreFleaCache

/**
 * <p> 核心Spring缓存类 </p>
 *
 * @author huazie
 * @version 1.0.0
 * @since 1.0.0
 */
public class CoreSpringCache extends AbstractSpringCache {
    
    

    /**
     * <p> 带参数构造方法 </p>
     *
     * @param name      缓存主关键字
     * @param fleaCache Flea Cache具体实现
     * @since 1.0.0
     */
    public CoreSpringCache(String name, IFleaCache fleaCache) {
    
    
        super(name, fleaCache);
    }

    /**
     * <p> 带参数构造方法 </p>
     *
     * @param name 缓存主关键字
     * @since 1.0.0
     */
    public CoreSpringCache(String name) {
    
    
        super(name, new CoreFleaCache(name));
    }
}

2. 定义核心Spring缓存管理类 CoreSpringCacheManager

该类继承抽象Spring缓存管理类 AbstractSpringCacheManager,用于对接Spring;基本实现同核心Flea缓存管理类 CoreFleaCacheManager,唯一不同在于 newCache 的实现,这边是new一个核心Spring缓存 CoreSpringCache

/**
 * <p> 核心Spring缓存管理类 </p>
 *
 * @author huazie
 * @version 1.0.0
 * @since 1.0.0
 */
public class CoreSpringCacheManager extends AbstractSpringCacheManager {
    
    

    @Override
    protected AbstractSpringCache newCache(String name, long expiry) {
    
    
        return new CoreSpringCache(name);
    }
}

3. Spring配置

<!-- 配置核心Flea缓存管理类 RedisSpringCacheManager -->
<bean id="coreSpringCacheManager" class="com.huazie.frame.cache.core.CoreSpringCacheManager" />

<!-- 开启缓存 -->
<cache:annotation-driven cache-manager="coreSpringCacheManager" proxy-target-class="true"/>

4. 缓存自测

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

5. 业务逻辑层接入缓存管理

@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接入的工作已经完成,相信各位已经能够接入系统~

猜你喜欢

转载自blog.csdn.net/u012855229/article/details/100016715