一、EHCACHE介绍
EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider。
优点:
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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util.xsdhttp://www.springframework.org/schema/jdbchttp://www.springframework.org/schema/jdbc/spring-jdbc.xsdhttp://www.springframework.org/schema/cachehttp://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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util.xsdhttp://www.springframework.org/schema/jdbchttp://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));
}
}
}