Ehcache与Spring整合

一、EHCACHE介绍

 

EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider。

ehcache

优点:

1. 快速

2. 简单

3. 多种缓存策略

4. 缓存数据有两级:内存和磁盘,因此无需担心容量问题

5. 缓存数据会在虚拟机重启的过程中写入磁盘

6. 可以通过RMI、可插入API等方式进行分布式缓存

7. 具有缓存和缓存管理器的侦听接口

8. 支持多缓存管理器实例,以及一个实例的多个缓存区域

9. 提供Hibernate的缓存实现

缺点

1. 使用磁盘Cache的时候非常占用磁盘空间:这是因为DiskCache的算法简单,该算法简单也导致Cache的效率非常高。它只是对元素直接追加存储。因此搜索元素的时候非常的快。如果使用DiskCache的,在很频繁的应用中,很快磁盘会满。

2. 不能保证数据的安全:当突然kill掉java的时候,可能会产生冲突,EhCache的解决方法是如果文件冲突了,则重建cache。这对于Cache 数据需要保存的时候可能不利。当然,Cache只是简单的加速,而不能保证数据的安全。如果想保证数据的存储安全,可以使用Bekeley DB Java Edition版本。这是个嵌入式数据库。可以确保存储安全和空间的利用率。

EhCache的分布式缓存有传统的RMI,1.5版的JGroups,1.6版的JMS。分布式缓存主要解决集群环境中不同的服务器间的数据的同步问题。

使用Spring的AOP进行整合,可以灵活的对方法的返回结果对象进行缓存。

参考:http://www.cnblogs.com/mxmbk/articles/5162813.html

           http://www.cnblogs.com/jianjianyang/p/4933016.html

二、与Spring整合

1. maven依赖
		<dependency>
			<groupId>net.sf.ehcache</groupId>
			<artifactId>ehcache-core</artifactId>
			<version>2.6.5</version>
		</dependency>
2、ehcache.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
	<!-- 磁盘存储:将缓存中暂时不使用的对象,转移到硬盘,类似于Windows系统的虚拟内存 path:指定在硬盘上存储对象的路径 -->
	<diskStore path="java.io.tmpdir" />
	<!-- defaultCache:默认的缓存配置信息,如果不加特殊说明,则所有对象按照此配置项处理 maxElementsInMemory:设置了缓存的上限,最多存储多少个记录对象 
		eternal:代表对象是否永不过期 timeToIdleSeconds:最大的发呆时间 timeToLiveSeconds:最大的存活时间 overflowToDisk:是否允许对象被写入到磁盘 -->
	<defaultCache maxElementsInMemory="1000" eternal="false"
		timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" />
	<!-- cache:为指定名称的对象进行缓存的特殊配置 name:指定对象的完整名 -->
	<cache name="ditItemCache" maxElementsInMemory="1000" eternal="false"
		timeToIdleSeconds="300" timeToLiveSeconds="600" overflowToDisk="true" />
</ehcache>
3、spring-cache.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:util="http://www.springframework.org/schema/util" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
	xmlns:cache="http://www.springframework.org/schema/cache"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd
    http://www.springframework.org/schema/util
    http://www.springframework.org/schema/util/spring-util.xsd
    http://www.springframework.org/schema/jdbc  
    http://www.springframework.org/schema/jdbc/spring-jdbc.xsd 
    http://www.springframework.org/schema/cache
    http://www.springframework.org/schema/cache/spring-cache.xsd">
	<!-- 开启cache注解扫描 -->
	<cache:annotation-driven />
	<!-- encache配置 -->
	<bean id="ehcacheManager"
		class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
		<property name="configLocation" value="classpath:cache/ehcache.xml" />
	</bean>
	<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
		<property name="cacheManager" ref="ehcacheManager" />
		<property name="transactionAware" value="true" />
	</bean>
</beans>
4、spring-basic.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:util="http://www.springframework.org/schema/util" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd
    http://www.springframework.org/schema/util
    http://www.springframework.org/schema/util/spring-util.xsd
    http://www.springframework.org/schema/jdbc  
    http://www.springframework.org/schema/jdbc/spring-jdbc.xsd ">
    	<context:component-scan base-package="com.yjpal.dams">
		<context:exclude-filter type="annotation"
			expression="org.springframework.stereotype.Controller" />
	</context:component-scan>
	<!-- 缓存配置 -->
	<import resource="classpath*:/cache/spring-cache.xml" />
</beans>
5、服务类实现(代码方式)
package com.yjpal.dams.common.service.impl;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.stereotype.Service;
 
/**
 * @Description: 缓存服务类
 * @author Jian Jang
 * @version 1.0 2017年8月16日
 */
@Service
public class EhCacheService {
    @Autowired
    private EhCacheCacheManager cacheManager;
 
    public EhCacheService() {
    }
    /**
     * 根据cacheKey从缓存中获取信息
     * @param cacheKey
     * @return
     * @throws Exception
     */
    public Object getCacheElement(String cacheKey) throws Exception {
        Cache cache = cacheManager.getCache("ditItemCache");
        Cache.ValueWrapper e = cache.get(cacheKey);
        if (null == e) {
            return null;
        }
        return e.get();
    }
 
    /**
     * 向缓存中添加信息
     * @param cacheKey
     * @param value
     */
    public void addElementTocache(String cacheKey, Object value) {
        Cache cache = cacheManager.getCache("ditItemCache");
        cache.put(cacheKey, value);
    }
}

6、示例代码(只展示逻辑,其他业务代码略)
package com.yjpal.dams.common.service.impl;
 
import java.util.List;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
 
import com.yjpal.dams.common.constant.CacheDictItemEnum;
import com.yjpal.dams.common.exceptions.BizException;
import com.yjpal.dams.common.service.CommonService;
import com.yjpal.dams.common.utils.JsonUtils;
import com.yjpal.dams.dbaccess.common.dao.CommonMapper;
import com.yjpal.dams.dbaccess.common.entity.DictItem;
 
/**
 * @Description: 公共服务实现类
 * @author Jian Jang
 * @version 1.0 2017年8月8日
 */
@Service
public class CommonServiceImpl implements CommonService {
    private transient Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private CommonMapper commonMapper;
    @Autowired
    private EhCacheService ehCacheService;
 
    @Override
    public List<DictItem> getDictItemList(DictItem dictItem) {
        try {
            // 此处需要省份和城市分开,省份-level=1 城市parentCode !=null
            if ("1".equals(dictItem.getLevel())) {
                return getRegion(dictItem, true);
            } else {
                return getRegion(dictItem, false);
            }
        } catch (Exception e) {
            logger.error("数据字典项查询失败:" + e.getMessage(), e);
        }
        return null;
    }
 
    /**
     * @param dictItem
     * @param flag true-省份 false-城市
     * @return
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    private List<DictItem> getRegion(DictItem dictItem, boolean flag) throws Exception {
        List<DictItem> dictItemList = null;
        // 先从缓存中获取
        if (flag) {
            dictItemList = (List<DictItem>) ehCacheService
                    .getCacheElement(CacheDictItemEnum.PROVINCE.getCode());
        } else {
            dictItemList = (List<DictItem>) ehCacheService
                    .getCacheElement(dictItem.getParentCode());
        }
        if (CollectionUtils.isEmpty(dictItemList)) {
            // 缓存为空从数据库中获取
            dictItemList = commonMapper.getDictItemList(dictItem);
            if (CollectionUtils.isEmpty(dictItemList)) {
                throw new BizException("省份/城市信息为空,加载失败。");
            } else {
                if (flag) {
                    // 将省份信息添加到缓存
                    ehCacheService.addElementTocache(CacheDictItemEnum.PROVINCE.getCode(),
                            dictItemList);
                    logger.info("从数据库中获取省份信息成功:{}", JsonUtils.list2JsonString(dictItemList));
                } else {
                    // 将城市信息添加到缓存
                    ehCacheService.addElementTocache(dictItem.getParentCode(), dictItemList);
                    logger.info("从数据库中获取城市信息成功:{}", JsonUtils.list2JsonString(dictItemList));
                }
                return dictItemList;
            }
        } else {
            if (flag) {
                logger.info("从缓存中获取省份信息成功:{}", JsonUtils.list2JsonString(dictItemList));
            } else {
                logger.info("从缓存中获取城市信息成功:{}", JsonUtils.list2JsonString(dictItemList));
 
            }
            return dictItemList;
        }
    }
 
    @SuppressWarnings("unchecked")
    @Override
    public List<DictItem> getTradeTypeList(DictItem dictItem) {
        List<DictItem> dictItemList = null;
        try {
            // 先从缓存汇总获取
            dictItemList = (List<DictItem>) ehCacheService
                    .getCacheElement(CacheDictItemEnum.TRADE_TYPE.getCode());
            if (CollectionUtils.isEmpty(dictItemList)) {
                // 从数据库中获取交易类型信息
                dictItemList = commonMapper.getTradeTypeList(dictItem);
                if (CollectionUtils.isEmpty(dictItemList)) {
                    throw new BizException("交易类型信息为空,加载失败。");
                } else {
                    // 将交易类型信息添加到缓存
                    ehCacheService.addElementTocache(CacheDictItemEnum.TRADE_TYPE.getCode(),
                            dictItemList);
                    logger.info("从数据库中获取交易类型信息成功:{}", JsonUtils.list2JsonString(dictItemList));
                    return dictItemList;
                }
            } else {
                logger.info("从缓存中获取交易类型信息成功:{}", JsonUtils.list2JsonString(dictItemList));
                return dictItemList;
            }
        } catch (Exception e) {
            logger.error("交易类型查询失败:" + e.getMessage(), e);
        }
        return null;
    }
 
    /**
     * 获取响应码信息
     * @param dictItem
     * @return
     */
    @Override
    @SuppressWarnings("unchecked")
    public List<DictItem> getRepCodeList(DictItem dictItem) {
        List<DictItem> dictItemList = null;
        try {
            // 先从缓存汇总获取
            dictItemList = (List<DictItem>) ehCacheService
                    .getCacheElement(CacheDictItemEnum.REP_CODE.getCode());
            if (CollectionUtils.isEmpty(dictItemList)) {
                // 从数据库中获取响应码信息
                dictItemList = commonMapper.getRepCodeList(dictItem);
                if (CollectionUtils.isEmpty(dictItemList)) {
                    throw new BizException("响应码信息为空,加载失败。");
                } else {
                    // 将响应码信息放到缓存中
                    ehCacheService.addElementTocache(CacheDictItemEnum.REP_CODE.getCode(),
                            dictItemList);
                    logger.info("从数据库中获取响应码信息成功:{}", JsonUtils.list2JsonString(dictItemList));
                    return dictItemList;
                }
            } else {
                logger.info("从缓存中获取响应码信息成功:{}", JsonUtils.list2JsonString(dictItemList));
                return dictItemList;
            }
        } catch (Exception e) {
            logger.error("响应码查询失败:" + e.getMessage(), e);
        }
        return null;
    }
 
    @SuppressWarnings("unchecked")
    @Override
    public List<DictItem> getAreaList(DictItem dictItem) {
        List<DictItem> dictItemList = null;
        try {
            // 先从缓存中获取
            dictItemList = (List<DictItem>) ehCacheService
                    .getCacheElement(CacheDictItemEnum.AREA_LIST.getCode());
            if (CollectionUtils.isEmpty(dictItemList)) {
                // 从数据库中获取区域信息
                dictItemList = commonMapper.getAreaList(dictItem);
                if (CollectionUtils.isEmpty(dictItemList)) {
                    throw new BizException("区域信息为空,加载失败。");
                } else {
                    // 将区域添加到缓存
                    ehCacheService.addElementTocache(CacheDictItemEnum.AREA_LIST.getCode(),
                            dictItemList);
                    logger.info("从数据库中获取区域信息成功:{}", JsonUtils.list2JsonString(dictItemList));
                    return dictItemList;
                }
            } else {
                logger.info("从缓存中获取区域信息成功:{}", JsonUtils.list2JsonString(dictItemList));
                return dictItemList;
            }
        } catch (Exception e) {
            logger.error("区域信息查询失败:" + e.getMessage(), e);
        }
        return null;
    }
 
    /**
     * 注解缓存测试
     * @param dictItem
     * @return
     */
    @Cacheable(value = "ditItemCache", key = "#dictItem.code")
    @Override
    public List<DictItem> getCacheTest(DictItem dictItem) {
        return commonMapper.getRepCodeList(dictItem);
    }
}

 

7.测试
package com.yjpal.dams.common.service.impl;
 
import java.util.List;
 
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
 
import com.yjpal.dams.common.service.CommonService;
import com.yjpal.dams.common.utils.JsonUtils;
import com.yjpal.dams.dbaccess.common.entity.DictItem;
import com.yjpal.dams.test.support.AbstractSpringContextTestSupport;
 
/**
 * @Description: 数据字典缓存测试
 * @author Jian Jang
 * @version 1.0 2017年8月16日
 */
public class CommonServiceImplTest extends AbstractSpringContextTestSupport {
    @Autowired
    private CommonService commonService;
 
    /**
     * Test method for
     * {@link com.yjpal.dams.common.service.impl.CommonServiceImpl#getDictItemList(com.yjpal.dams.dbaccess.common.entity.DictItem)}
     * .
     */
    @Test
    public void testGetDictItemList() {
        try {
            DictItem dictItem = new DictItem();
            dictItem.setLevel("1");
            // dictItem.setParentCode("3300");
            List<DictItem> list = commonService.getDictItemList(dictItem);
            System.out.println(JsonUtils.list2JsonString(list));
            list = commonService.getDictItemList(dictItem);
            System.out.println(JsonUtils.list2JsonString(list));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
    /**
     * Test method for
     * {@link com.yjpal.dams.common.service.impl.CommonServiceImpl#getCacheTest(com.yjpal.dams.dbaccess.common.entity.DictItem)}
     * .
     */
    @Test
    public void testgetCacheTest() {
        DictItem dictItem = new DictItem();
        dictItem.setCode("cacheTest");
        for (int i = 0; i < 5; i++) {
            List<DictItem> list = commonService.getCacheTest(dictItem);
            System.out.println(JsonUtils.list2JsonString(list));
        }
 
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值