spring ehcache 使用详解
Spring 整合 Ehcache 管理缓存详解
前言
Ehcache 是一个成熟的缓存框架,你可以直接使用它来管理你的缓存。
Spring 提供了对缓存功能的抽象:即允许绑定不同的缓存解决方案(如Ehcache),但本身不直接提供缓存功能的实现。它支持注解方式使用缓存,非常方便。
本文先通过Ehcache独立应用的范例来介绍它的基本使用方法,然后再介绍与Spring整合的方法。
概述
Ehcache是什么?
EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点。它是Hibernate中的默认缓存框架。
Ehcache已经发布了3.1版本。但是本文的讲解基于2.10.2版本。
为什么不使用最新版呢?因为Spring4还不能直接整合Ehcache 3.x。虽然可以通过JCache间接整合,Ehcache也支持JCache,但是个人觉得不是很方便。
安装
Ehcache
如果你的项目使用maven管理,添加以下依赖到你的pom.xml中。
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.2</version>
<type>pom</type>
</dependency>
如果你的项目不使用maven管理,请在 Ehcache官网下载地址 下载jar包。
Spring
如果你的项目使用maven管理,添加以下依赖到你的pom.xml中。
spring-context-support
这个jar包中含有Spring对于缓存功能的抽象封装接口。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>
Ehcache的使用
HelloWorld范例
接触一种技术最快最直接的途径总是一个Hello World例子,毕竟动手实践印象更深刻,不是吗?
(1) 在classpath下添加ehcache.xml
添加一个名为helloworld的缓存。
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"> <!-- 磁盘缓存位置 -->
<diskStore path="java.io.tmpdir/ehcache"/> <!-- 默认缓存 -->
<defaultCache
maxEntriesLocalHeap="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxEntriesLocalDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"/> <!-- helloworld缓存 -->
<cache name="helloworld"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="5"
timeToLiveSeconds="5"
overflowToDisk="false"
memoryStoreEvictionPolicy="LRU"/>
</ehcache>
(2) EhcacheDemo.java
Ehcache会自动加载classpath根目录下名为ehcache.xml文件。
EhcacheDemo的工作步骤如下:
在EhcacheDemo中,我们引用ehcache.xml声明的名为helloworld的缓存来创建Cache
对象;
然后我们用一个键值对来实例化Element
对象;
将Element
对象添加到Cache
;
然后用Cache
的get方法获取Element
对象。
public class EhcacheDemo {
public static void main(String[] args) throws Exception {
// Create a cache manager
final CacheManager cacheManager = new CacheManager(); // create the cache called "helloworld"
final Cache cache = cacheManager.getCache("helloworld"); // create a key to map the data to
final String key = "greeting"; // Create a data element
final Element putGreeting = new Element(key, "Hello, World!"); // Put the element into the data store
cache.put(putGreeting); // Retrieve the data element
final Element getGreeting = cache.get(key); // Print the value
System.out.println(getGreeting.getObjectValue());
}
}
输出
Hello, World!
Ehcache基本操作
Element
、Cache
、CacheManager
是Ehcache最重要的API。
- Element:缓存的元素,它维护着一个键值对。
- Cache:它是Ehcache的核心类,它有多个
Element
,并被CacheManager
管理。它实现了对缓存的逻辑行为。 - CacheManager:
Cache
的容器对象,并管理着Cache
的生命周期。
创建CacheManager
下面的代码列举了创建CacheManager
的五种方式。
使用静态方法create()
会以默认配置来创建单例的CacheManager
实例。newInstance()
方法是一个工厂方法,以默认配置创建一个新的CacheManager
实例。
此外,newInstance()
还有几个重载函数,分别可以通过传入String
、URL
、InputStream
参数来加载配置文件,然后创建CacheManager
实例。
// 使用Ehcache默认配置获取单例的CacheManager实例
CacheManager.create();
String[] cacheNames = CacheManager.getInstance().getCacheNames(); // 使用Ehcache默认配置新建一个CacheManager实例
CacheManager.newInstance();
String[] cacheNames = manager.getCacheNames(); // 使用不同的配置文件分别创建一个CacheManager实例
CacheManager manager1 = CacheManager.newInstance("src/config/ehcache1.xml");
CacheManager manager2 = CacheManager.newInstance("src/config/ehcache2.xml");
String[] cacheNamesForManager1 = manager1.getCacheNames();
String[] cacheNamesForManager2 = manager2.getCacheNames(); // 基于classpath下的配置文件创建CacheManager实例
URL url = getClass().getResource("/anotherconfigurationname.xml");
CacheManager manager = CacheManager.newInstance(url); // 基于文件流得到配置文件,并创建CacheManager实例
InputStream fis = new FileInputStream(new File
("src/config/ehcache.xml").getAbsolutePath());
try {
CacheManager manager = CacheManager.newInstance(fis);
} finally {
fis.close();
}
添加缓存
需要强调一点,Cache
对象在用addCache
方法添加到CacheManager
之前,是无效的。
使用CacheManager的addCache方法可以根据缓存名将ehcache.xml中声明的cache添加到容器中;它也可以直接将Cache对象添加到缓存容器中。
Cache
有多个构造函数,提供了不同方式去加载缓存的配置参数。
有时候,你可能需要使用API来动态的添加缓存,下面的例子就提供了这样的范例。
// 除了可以使用xml文件中配置的缓存,你也可以使用API动态增删缓存
// 添加缓存
manager.addCache(cacheName); // 使用默认配置添加缓存
CacheManager singletonManager = CacheManager.create();
singletonManager.addCache("testCache");
Cache test = singletonManager.getCache("testCache"); // 使用自定义配置添加缓存,注意缓存未添加进CacheManager之前并不可用
CacheManager singletonManager = CacheManager.create();
Cache memoryOnlyCache = new Cache("testCache", 5000, false, false, 5, 2);
singletonManager.addCache(memoryOnlyCache);
Cache test = singletonManager.getCache("testCache"); // 使用特定的配置添加缓存
CacheManager manager = CacheManager.create();
Cache testCache = new Cache(
new CacheConfiguration("testCache", maxEntriesLocalHeap)
.memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.LFU)
.eternal(false)
.timeToLiveSeconds(60)
.timeToIdleSeconds(30)
.diskExpiryThreadIntervalSeconds(0)
.persistence(new PersistenceConfiguration().strategy(Strategy.LOCALTEMPSWAP)));
manager.addCache(testCache);
删除缓存
删除缓存比较简单,你只需要将指定的缓存名传入removeCache
方法即可。
CacheManager singletonManager = CacheManager.create();
singletonManager.removeCache("sampleCache1");
实现基本缓存操作
Cache最重要的两个方法就是put和get,分别用来添加Element和获取Element。
Cache还提供了一系列的get、set方法来设置或获取缓存参数,这里不一一列举,更多API操作可参考官方API开发手册。
/**
* 测试:使用默认配置或使用指定配置来创建CacheManager
*
* @author victor zhang
*/
public class CacheOperationTest {
private final Logger log = LoggerFactory.getLogger(CacheOperationTest.class); /**
* 使用Ehcache默认配置(classpath下的ehcache.xml)获取单例的CacheManager实例
*/
@Test
public void operation() {
CacheManager manager = CacheManager.newInstance("src/test/resources/ehcache/ehcache.xml"); // 获得Cache的引用
Cache cache = manager.getCache("userCache"); // 将一个Element添加到Cache
cache.put(new Element("key1", "value1")); // 获取Element,Element类支持序列化,所以下面两种方法都可以用
Element element1 = cache.get("key1");
// 获取非序列化的值
log.debug("key:{}, value:{}", element1.getObjectKey(), element1.getObjectValue());
// 获取序列化的值
log.debug("key:{}, value:{}", element1.getKey(), element1.getValue()); // 更新Cache中的Element
cache.put(new Element("key1", "value2"));
Element element2 = cache.get("key1");
log.debug("key:{}, value:{}", element2.getObjectKey(), element2.getObjectValue()); // 获取Cache的元素数
log.debug("cache size:{}", cache.getSize()); // 获取MemoryStore的元素数
log.debug("MemoryStoreSize:{}", cache.getMemoryStoreSize()); // 获取DiskStore的元素数
log.debug("DiskStoreSize:{}", cache.getDiskStoreSize()); // 移除Element
cache.remove("key1");
log.debug("cache size:{}", cache.getSize()); // 关闭当前CacheManager对象
manager.shutdown(); // 关闭CacheManager单例实例
CacheManager.getInstance().shutdown();
}
}
缓存配置
Ehcache支持通过xml文件和API两种方式进行配置。
xml方式
Ehcache的CacheManager
构造函数或工厂方法被调用时,会默认加载classpath下名为ehcache.xml的配置文件。如果加载失败,会加载Ehcache jar包中的ehcache-failsafe.xml文件,这个文件中含有简单的默认配置。
ehcache.xml配置参数说明:
- name:缓存名称。
- maxElementsInMemory:缓存最大个数。
- eternal:缓存中对象是否为永久的,如果是,超时设置将被忽略,对象从不过期。
- timeToIdleSeconds:置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
- timeToLiveSeconds:缓存数据的生存时间(TTL),也就是一个元素从构建到消亡的最大时间间隔值,这只能在元素不是永久驻留时有效,如果该值是0就意味着元素可以停顿无穷长的时间。
- maxEntriesLocalDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。
- overflowToDisk:内存不足时,是否启用磁盘缓存。
- diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
- maxElementsOnDisk:硬盘最大缓存个数。
- diskPersistent:是否在VM重启时存储硬盘的缓存数据。默认值是false。
- diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
- memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
- clearOnFlush:内存数量最大时是否清除。
ehcache.xml的一个范例
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"> <!-- 磁盘缓存位置 -->
<diskStore path="java.io.tmpdir/ehcache"/> <!-- 默认缓存 -->
<defaultCache
maxEntriesLocalHeap="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxEntriesLocalDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<persistence strategy="localTempSwap"/>
</defaultCache> <cache name="userCache"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="3"
timeToLiveSeconds="3"
maxEntriesLocalDisk="10000000"
overflowToDisk="false"
memoryStoreEvictionPolicy="LRU"/>
</ehcache>
API方式
xml配置的参数也可以直接通过编程方式来动态的进行配置(dynamicConfig没有设为false)。
Cache cache = manager.getCache("sampleCache");
CacheConfiguration config = cache.getCacheConfiguration();
config.setTimeToIdleSeconds(60);
config.setTimeToLiveSeconds(120);
config.setmaxEntriesLocalHeap(10000);
config.setmaxEntriesLocalDisk(1000000);
也可以通过disableDynamicFeatures()
方式关闭动态配置开关。配置以后你将无法再以编程方式配置参数。
Cache cache = manager.getCache("sampleCache");
cache.disableDynamicFeatures();
Spring整合Ehcache
Spring3.1开始添加了对缓存的支持。和事务功能的支持方式类似,缓存抽象允许底层使用不同的缓存解决方案来进行整合。
Spring4.1开始支持JSR-107注解。
注:我本人使用的Spring版本为4.1.4.RELEASE,目前Spring版本仅支持Ehcache2.5以上版本,但不支持Ehcache3。
绑定Ehcache
org.springframework.cache.ehcache.EhCacheManagerFactoryBean
这个类的作用是加载Ehcache配置文件。org.springframework.cache.ehcache.EhCacheCacheManager
这个类的作用是支持net.sf.ehcache.CacheManager。
spring-ehcache.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:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.2.xsd"> <description>ehcache缓存配置管理文件</description> <bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache/ehcache.xml"/>
</bean> <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehcache"/>
</bean> <!-- 启用缓存注解开关 -->
<cache:annotation-driven cache-manager="cacheManager"/>
</beans>
使用Spring的缓存注解
开启注解
Spring为缓存功能提供了注解功能,但是你必须启动注解。
你有两个选择:
(1) 在xml中声明
像上一节spring-ehcache.xml中的做法一样,使用<cache:annotation-driven/>
<cache:annotation-driven cache-manager="cacheManager"/>
(2) 使用标记注解
你也可以通过对一个类进行注解修饰的方式在这个类中使用缓存注解。
范例如下:
@Configuration
@EnableCaching
public class AppConfig {
}
注解基本使用方法
Spring对缓存的支持类似于对事务的支持。
首先使用注解标记方法,相当于定义了切点,然后使用Aop技术在这个方法的调用前、调用后获取方法的入参和返回值,进而实现了缓存的逻辑。
下面三个注解都是方法级别:
@Cacheable
表明所修饰的方法是可以缓存的:当第一次调用这个方法时,它的结果会被缓存下来,在缓存的有效时间内,以后访问这个方法都直接返回缓存结果,不再执行方法中的代码段。
这个注解可以用condition
属性来设置条件,如果不满足条件,就不使用缓存能力,直接执行方法。
可以使用key
属性来指定key的生成规则。
@CachePut
与@Cacheable
不同,@CachePut
不仅会缓存方法的结果,还会执行方法的代码段。
它支持的属性和用法都与@Cacheable
一致。
@CacheEvict
与@Cacheable
功能相反,@CacheEvict
表明所修饰的方法是用来删除失效或无用的缓存数据。
下面是@Cacheable
、@CacheEvict
和@CachePut
基本使用方法的一个集中展示:
@Service
public class UserService {
// @Cacheable可以设置多个缓存,形式如:@Cacheable({"books", "isbns"})
@Cacheable({"users"})
public User findUser(User user) {
return findUserInDB(user.getId());
} @Cacheable(value = "users", condition = "#user.getId() <= 2")
public User findUserInLimit(User user) {
return findUserInDB(user.getId());
} @CachePut(value = "users", key = "#user.getId()")
public void updateUser(User user) {
updateUserInDB(user);
} @CacheEvict(value = "users")
public void removeUser(User user) {
removeUserInDB(user.getId());
} @CacheEvict(value = "users", allEntries = true)
public void clear() {
removeAllInDB();
}
}
@Caching
如果需要使用同一个缓存注解(@Cacheable
、@CacheEvict
或@CachePut
)多次修饰一个方法,就需要用到@Caching
。
@Caching(evict = { @CacheEvict("primary"), @CacheEvict(cacheNames="secondary", key="#p0") })
public Book importBooks(String deposit, Date date)
@CacheConfig
与前面的缓存注解不同,这是一个类级别的注解。
如果类的所有操作都是缓存操作,你可以使用@CacheConfig
来指定类,省去一些配置。
@CacheConfig("books")
public class BookRepositoryImpl implements BookRepository {
@Cacheable
public Book findBook(ISBN isbn) {...}
}
参考
如果想参考我的完整代码示例,请点击这里访问我的github。
下面是我在写作时参考的资料或文章。
spring ehcache 使用详解的更多相关文章
- (转)Spring JdbcTemplate 方法详解
Spring JdbcTemplate方法详解 文章来源:http://blog.csdn.net/dyllove98/article/details/7772463 JdbcTemplate主要提供 ...
- Spring jar包详解
Spring jar包详解 org.springframework.aop ——Spring的面向切面编程,提供AOP(面向切面编程)的实现 org.springframework.asm——spri ...
- Spring——jar包详解(转)
Spring——jar包详解 org.springframework.aop ——Spring的面向切面编程,提供AOP(面向切面编程)的实现 org.springframework.asm——spr ...
- Spring Boot异常处理详解
在Spring MVC异常处理详解中,介绍了Spring MVC的异常处理体系,本文将讲解在此基础上Spring Boot为我们做了哪些工作.下图列出了Spring Boot中跟MVC异常处理相关的类 ...
- spring事务配置详解
一.前言 好几天没有在对spring进行学习了,由于这几天在赶项目,没有什么时间闲下来继续学习,导致spring核心架构详解没有继续下去,在接下来的时间里面,会继续对spring的核心架构在继续进行学 ...
- spring注入参数详解
spring注入参数详解 在Spring配置文件中, 用户不但可以将String, int等字面值注入到Bean中, 还可以将集合, Map等类型的数据注入到Bean中, 此外还可以注入配置文件中定义 ...
- Spring的lazy-init详解
1.Spring中lazy-init详解ApplicationContext实现的默认行为就是在启动服务器时将所有singleton bean提前进行实例化(也就是依赖注入).提前实例化意味着作为初始 ...
- Spring Security Filter详解
Spring Security Filter详解 汇总 Filter 作用 DelegatingFilterProxy Spring Security基于这个Filter建立拦截机制 Abstract ...
- Spring Boot 配置文件详解
Spring Boot配置文件详解 Spring Boot提供了两种常用的配置文件,分别是properties文件和yml文件.他们的作用都是修改Spring Boot自动配置的默认值.相对于prop ...
随机推荐
- Debian安装Docker
Debian 安装 Docker CE 准备工作 系统要求 Docker CE 支持以下版本的 Debian 操作系统: Stretch 9 Jessie 8 (LTS) Wheezy 7.7 (LT ...
- spring 4.0 JUnit简单的Controller测试
比Dao和Service的测试稍微复杂一点.还是先写一个BasicWebTest用来总体配置: @WebAppConfiguration @ContextConfiguration(locations ...
- Learning Python 008 正则表达式-003 sub()方法
Python 正则表达式 - sub()方法 sub()方法 sub()方法:替换符合规律的内容,返回替换的值 # -?- coding: utf-8 -?- import re secret_cod ...
- KINECT2通过ROS在线跑ORBSLAM2
source ~/.bashrc export ROS_PACKAGE_PATH=${ROS_PACKAGE_PATH}:/home/user/ORB_SLAM2/Examples/ROS 上面这个一 ...
- Asp.Net 之 Web.config 配置文件详解 -转
在asp.net中配置文件名一般默认是web.config.每个web.config文件都是基于XML的文本文件,并且可以保存到Web应用程序中的任何目录中.在发布Web应用程序时web.config ...
- [CentOS7] iconv编程转换
声明:本文主要总结自:鸟哥的Linux私房菜-第九章.vim 程式編輯器,如有侵权,请通知博主 (-- 源自鸟哥的私房菜) 首先用Notepad++新建个文件来做这个实验,在Windows平台下新建个 ...
- CodeForces 114B 【STL应用】
思路: 原来string类能sort 和 swap....太强了.... 注意:字典序最小输出,因为某个地方写挫了,sort了n发,代码挫. #include <bits/stdc++.h> ...
- CSS基本
CSS选择器优先级:从高到低 无条件优先的属性只需要在属性后面使用!important,但是IE6不支持.解决办法,IE6是单个支持的. 例如: 在IE6中需要这样写 .className{color ...
- angularJs解决模态框下echarts不显示问题
例如:摸态框myModal.html,给它命名一个id,id='myModal'; myModal.html页面想画一个echarts图表 这里是angularJs已经封装好的echarts在html ...
- 洛谷 P1551 亲戚(并查集模板)
嗯... 题目链接:https://www.luogu.org/problemnew/show/P1551 思路: 很显然地我们会发现,这是一道并查集的模板题,并且是考察了并查集中的”并“和”查“的操 ...