官方文档:http://www.ehcache.org/generated/2.9.0/html/ehc-all/html
参考文档:java
http://www.cnblogs.com/jingmoxukong/p/5975994.html#_label13spring
http://blog.csdn.net/u012106290/article/details/52154367数据库
关于EHCache3.x版本的使用详见此篇博客:缓存
http://www.javashuo.com/article/p-bceierkl-hz.htmldom
Maven依赖:jvm
<dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> <version>2.10.3</version> </dependency>
在class根目录下加入配置文件ehcache1.xml.ide
<?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" /> <!-- helloworld1缓存 --> <cache name = "hello-world1" maxElementsInMemory = "1000" eternal = "false" timeToIdleSeconds = "5" timeToLiveSeconds = "5" overflowToDisk = "false" memoryStoreEvictionPolicy = "LRU" /> </ehcache>
Java代码以下:测试
public static void main(String[] args) { // Create a cache manager final CacheManager cacheManager = CacheManager.newInstance(EHCacheTest.class .getResource("/ehcache1.xml")); // create the cache called "hello-world" final Cache cache = cacheManager.getCache("hello-world1"); // 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()); }
输出结果以下(包括日志):this
DEBUG 18:15:24,365 [main](ConfigurationFactory.java:98) - Configuring ehcache from URL: file:/D:/WORKSPACE/intelljIdea/SSMProjectMaven/target/test-classes/ehcache1.xml DEBUG 18:15:24,371 [main](ConfigurationFactory.java:150) - Configuring ehcache from InputStream DEBUG 18:15:24,466 [main](BeanHandler.java:271) - Ignoring ehcache attribute xmlns:xsi DEBUG 18:15:24,466 [main](BeanHandler.java:271) - Ignoring ehcache attribute xsi:noNamespaceSchemaLocation DEBUG 18:15:24,474 [main](DiskStoreConfiguration.java:141) - Disk Store Path: C:\Users\FlyingHe\AppData\Local\Temp\/ehcache DEBUG 18:15:24,526 [main](CacheManager.java:1102) - Creating new CacheManager with config URL: file:/D:/WORKSPACE/intelljIdea/SSMProjectMaven/target/test-classes/ehcache1.xml DEBUG 18:15:24,531 [main](PropertyUtil.java:87) - propertiesString is null. DEBUG 18:15:24,553 [main](ConfigurationHelper.java:189) - No CacheManagerEventListenerFactory class specified. Skipping... DEBUG 18:15:25,168 [main](Cache.java:1044) - No BootstrapCacheLoaderFactory class specified. Skipping... DEBUG 18:15:25,169 [main](Cache.java:1017) - CacheWriter factory not configured. Skipping... DEBUG 18:15:25,169 [main](ConfigurationHelper.java:100) - No CacheExceptionHandlerFactory class specified. Skipping... DEBUG 18:15:25,189 [main](Cache.java:1044) - No BootstrapCacheLoaderFactory class specified. Skipping... DEBUG 18:15:25,189 [main](Cache.java:1017) - CacheWriter factory not configured. Skipping... DEBUG 18:15:25,190 [main](ConfigurationHelper.java:100) - No CacheExceptionHandlerFactory class specified. Skipping... DEBUG 18:15:25,243 [main](MemoryStore.java:180) - Initialized net.sf.ehcache.store.MemoryStore for hello-world1 DEBUG 18:15:25,406 [main](ExtendedStatisticsImpl.java:224) - Mocking Pass-Through Statistic: LOCAL_OFFHEAP_SIZE DEBUG 18:15:25,414 [main](ExtendedStatisticsImpl.java:224) - Mocking Pass-Through Statistic: LOCAL_OFFHEAP_SIZE_BYTES DEBUG 18:15:25,415 [main](ExtendedStatisticsImpl.java:224) - Mocking Pass-Through Statistic: LOCAL_DISK_SIZE DEBUG 18:15:25,416 [main](ExtendedStatisticsImpl.java:224) - Mocking Pass-Through Statistic: LOCAL_DISK_SIZE_BYTES DEBUG 18:15:25,417 [main](ExtendedStatisticsImpl.java:224) - Mocking Pass-Through Statistic: WRITER_QUEUE_LENGTH DEBUG 18:15:25,419 [main](ExtendedStatisticsImpl.java:224) - Mocking Pass-Through Statistic: REMOTE_SIZE DEBUG 18:15:25,419 [main](ExtendedStatisticsImpl.java:224) - Mocking Pass-Through Statistic: LAST_REJOIN_TIMESTAMP DEBUG 18:15:25,516 [main](ExtendedStatisticsImpl.java:206) - Mocking Operation Statistic: OFFHEAP_GET DEBUG 18:15:25,518 [main](ExtendedStatisticsImpl.java:206) - Mocking Operation Statistic: OFFHEAP_PUT DEBUG 18:15:25,519 [main](ExtendedStatisticsImpl.java:206) - Mocking Operation Statistic: OFFHEAP_REMOVE DEBUG 18:15:25,522 [main](ExtendedStatisticsImpl.java:206) - Mocking Operation Statistic: DISK_GET DEBUG 18:15:25,523 [main](ExtendedStatisticsImpl.java:206) - Mocking Operation Statistic: DISK_PUT DEBUG 18:15:25,524 [main](ExtendedStatisticsImpl.java:206) - Mocking Operation Statistic: DISK_REMOVE DEBUG 18:15:25,525 [main](ExtendedStatisticsImpl.java:206) - Mocking Operation Statistic: XA_COMMIT DEBUG 18:15:25,526 [main](ExtendedStatisticsImpl.java:206) - Mocking Operation Statistic: XA_ROLLBACK DEBUG 18:15:25,556 [main](ExtendedStatisticsImpl.java:206) - Mocking Operation Statistic: XA_RECOVERY DEBUG 18:15:25,565 [main](ExtendedStatisticsImpl.java:206) - Mocking Operation Statistic: CLUSTER_EVENT DEBUG 18:15:25,566 [main](ExtendedStatisticsImpl.java:206) - Mocking Operation Statistic: NONSTOP DEBUG 18:15:25,578 [main](Cache.java:1262) - Initialised cache: hello-world1 DEBUG 18:15:25,578 [main](ConfigurationHelper.java:334) - CacheDecoratorFactory not configured. Skipping for 'hello-world1'. DEBUG 18:15:25,578 [main](ConfigurationHelper.java:364) - CacheDecoratorFactory not configured for defaultCache. Skipping for 'hello-world1'. Hello, World!
注:
若是在实例化CacheManager时采用此种方式CacheManager manager = CacheManager.newInstance();则默认加载class根目录下的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"/> <defaultCache maxElementsInMemory="10000" maxElementsOnDisk="0" eternal="true" overflowToDisk="true" diskPersistent="false" timeToIdleSeconds="0" timeToLiveSeconds="0" diskSpoolBufferSizeMB="50" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LFU" /> <cache name="myCache" maxElementsInMemory="100" maxElementsOnDisk="0" eternal="false" overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="120" timeToLiveSeconds="120" diskSpoolBufferSizeMB="50" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="FIFO" /> </ehcache>
解释以下:
一、diskStore :指定数据(.data and .index)存储位置,可指定磁盘中的文件夹位置期 The diskStore element is optional. It must be configured if you have overflowToDisk or diskPersistent enabled for any cache. If it is not configured, a warning will be issues and java.io.tmpdir will be used. 2、defaultCache : 默认的管理策略 1、如下属性是必须的: 一、name: Cache的名称,必须是惟一的(ehcache会把这个cache放到HashMap里)。 二、maxElementsInMemory:在内存中缓存的element的最大数目。 三、maxElementsOnDisk:在磁盘上缓存的element的最大数目,默认值为0,表示不限制。 4、eternal:设定缓存的elements是否永远不过时。若是为true,则缓存的数据始终有效,若是为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断。 5、overflowToDisk: 若是内存中数据超过内存限制,是否要缓存到磁盘上。 2、如下属性是可选的: 1、timeToIdleSeconds: 对象空闲时间,指对象在多长时间没有被访问就会失效。只对eternal为false的有效。默认值0,表示一直能够访问。 2、timeToLiveSeconds: 对象存活时间,指对象从建立到失效所须要的时间。只对eternal为false的有效。默认值0,表示一直能够访问。 3、diskPersistent: 是否在磁盘上持久化。指重启jvm后,数据是否有效。默认为false。 4、diskExpiryThreadIntervalSeconds: 对象检测线程运行时间间隔。标识对象状态的线程多长时间运行一次。 5、diskSpoolBufferSizeMB: DiskStore使用的磁盘大小,默认值30MB。每一个cache使用各自的DiskStore。 6、memoryStoreEvictionPolicy: 若是内存中数据超过内存限制,向磁盘缓存时的策略。默认值LRU,可选FIFO、LFU。 4、缓存的3 种清空策略 : 1、FIFO ,first in first out (先进先出). 2、LFU , Less Frequently Used (最少使用).意思是一直以来最少被使用的。缓存的元素有一个hit 属性,hit 值最小的将会被清出缓存。 3、LRU ,Least Recently Used(最近最少使用). (ehcache 默认值).缓存的元素有一个时间戳,当缓存容量满了,而又须要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
引入Spring相关的包这里再也不详述。
①建立一个ehcache-spring.xml的文件,配置Spring
<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.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd"> <!--开启Spring的缓存注解,以便使用Cacheable,CachePut,CacheEvict等注解--> <cache:annotation-driven /> <bean id = "personService" class = "at.flying.service.PersonService" /> <!-- 用于读取EHCache配置文件,注意这里暴露的bean并非 org.springframework.cache.ehcache.EhCacheManagerFactoryBean 这个类的实例,而是net.sf.ehcache.CacheManager的实例 --> <bean id = "ehcacheFactoryBean" class = "org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <property name = "configLocation" value = "classpath:ehcache1.xml" /> </bean> <!--使用EHCache配置文件建立CacheManager,拿到了CacheManager不就想干吗干吗了嘛^-^ --> <bean id = "cacheManager" class = "org.springframework.cache.ehcache.EhCacheCacheManager"> <property name = "cacheManager" ref = "ehcacheFactoryBean" /> </bean> </beans>
②建立ehcache1.xml文件,配置EHCache
<?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" /> <!-- Person缓存 --> <cache name = "Person" maxElementsInMemory = "1000" eternal = "false" timeToIdleSeconds = "3" timeToLiveSeconds = "3" overflowToDisk = "false" memoryStoreEvictionPolicy = "LRU" /> </ehcache>
③建立一个Person类,须要缓存的对象的所属类必须实现java.io.Serializable接口
package at.flying.domain; import java.io.Serializable; public class Person implements Serializable { private static final long serialVersionUID = 1L; private int id; private String name; public Person() {} public Person(int id, String name) { this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "id=" + this.id + ", name=" + this.name; } }
④建立一个PersonService类,用于模拟对数据库操做的业务逻辑
package at.flying.service; import at.flying.domain.Person; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import java.util.HashSet; import java.util.Set; public class PersonService { private Set<Person> people; public PersonService() { people = new HashSet<>(); Person person1 = new Person(1, "张三"); Person person2 = new Person(2, "赵四"); Person person3 = new Person(3, "王五"); people.add(person1); people.add(person2); people.add(person3); } @Cacheable({"Person"}) public Person findUser(Person person) { return findUserInDB(person.getId()); } @Cacheable(value = "Person", condition = "#person.getId() <= 2") public Person findUserInLimit(Person person) { return findUserInDB(person.getId()); } @CachePut(value = "Person") public Person updateUser(Person person) { updateUserInDB(person); return person; } @CacheEvict(value = "Person") public void removeUser(Person person) { removeUserInDB(person.getId()); } @CacheEvict(value = "Person", allEntries = true) public void clear() { removeAllInDB(); } /** * 模拟查找数据库 */ private Person findUserInDB(int id) { for (Person u : people) { if (id == u.getId()) { System.out.println("查找数据库 id = " + id + " 成功"); return u; } } return null; } /** * 模拟更新数据库 */ private void updateUserInDB(Person person) { for (Person u : people) { if (person.getId() == u.getId()) { System.out.println("更新数据库" + u + " -> " + person); u.setName(person.getName()); } } } private void removeUserInDB(int id) { for (Person u : people) { if (id == u.getId()) { System.out.println("从数据库移除 id = " + id + " 的数据"); people.remove(u); break; } } } private void removeAllInDB() { people.clear(); } }
⑤测试类EHCacheSpringTest
package at.flying.test; import at.flying.domain.Person; import at.flying.service.PersonService; import net.sf.ehcache.Element; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.ehcache.EhCacheCacheManager; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import java.util.List; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:at/flying/ehcache/spring/xml/ehcache-spring.xml"}) public class EHCacheSpringTest { @Autowired PersonService personService; @Autowired EhCacheCacheManager cacheManager; /** * 测试@Cacheable */ @Test public void testFindUser() throws InterruptedException { // 设置查询条件 Person person1 = new Person(1, null); Person person2 = new Person(2, null); Person person3 = new Person(3, null); System.out.println("第一次查询"); System.out.println(personService.findUser(person1)); System.out.println(personService.findUser(person2)); System.out.println(personService.findUser(person3)); this.printCacheStatus(); System.out.println("\n第二次查询"); System.out.println(personService.findUser(person1)); System.out.println(personService.findUser(person2)); System.out.println(personService.findUser(person3)); // 在classpath:ehcache/ehcache.xml中,设置了userCache的缓存时间为3000 ms, 这里设置等待 Thread.sleep(3000); System.out.println("\n缓存过时,再次查询"); System.out.println(personService.findUser(person1)); System.out.println(personService.findUser(person2)); System.out.println(personService.findUser(person3)); } /** * 输出当前Person缓存的缓存信息 */ public void printCacheStatus() { net.sf.ehcache.CacheManager cacheManager = this.cacheManager.getCacheManager(); net.sf.ehcache.Cache cache = cacheManager.getCache("Person"); System.out.println("缓存对象数:" + cache.getSize()); System.out.println("各元素的Key-Value以下:"); List keys = cache.getKeys(); for (Object o : keys) { Element e = cache.get(o); System.out.println(o + " -> " + e.getObjectValue()); } } /** * 测试@Cacheable设置Spring SpEL条件限制 */ @Test public void testFindUserInLimit() throws InterruptedException { // 设置查询条件 Person person1 = new Person(1, null); Person person2 = new Person(2, null); Person person3 = new Person(3, null); System.out.println("第一次查询user info"); System.out.println(personService.findUserInLimit(person1)); System.out.println(personService.findUserInLimit(person2)); System.out.println(personService.findUserInLimit(person3)); System.out.println("\n第二次查询user info"); System.out.println(personService.findUserInLimit(person1)); System.out.println(personService.findUserInLimit(person2)); System.out.println(personService.findUserInLimit(person3)); // 超过限制条件,不会从缓存中读数据 // 在classpath:ehcache/ehcache.xml中,设置了userCache的缓存时间为3000 ms, 这里设置等待 Thread.sleep(3000); System.out.println("\n缓存过时,再次查询"); System.out.println(personService.findUserInLimit(person1)); System.out.println(personService.findUserInLimit(person2)); System.out.println(personService.findUserInLimit(person3)); } /** * 测试@CachePut */ @Test public void testUpdateUser() { // 设置查询条件 Person person2 = new Person(2, null); System.out.println(personService.findUser(person2)); this.printCacheStatus(); personService.updateUser(new Person(2, "尼古拉斯.赵四")); this.printCacheStatus(); System.out.println(personService.findUser(person2)); } /** * 测试@CacheEvict删除指定缓存 */ @Test public void testRemoveUser() { // 设置查询条件 Person person1 = new Person(1, null); System.out.println("数据删除前:"); System.out.println(personService.findUser(person1)); personService.removeUser(person1); System.out.println("数据删除后:"); System.out.println(personService.findUser(person1)); } /** * 测试@CacheEvict删除全部缓存 */ @Test public void testClear() { System.out.println("数据清空前:"); System.out.println(personService.findUser(new Person(1, null))); System.out.println(personService.findUser(new Person(2, null))); System.out.println(personService.findUser(new Person(3, null))); personService.clear(); System.out.println("\n数据清空后:"); System.out.println(personService.findUser(new Person(1, null))); System.out.println(personService.findUser(new Person(2, null))); System.out.println(personService.findUser(new Person(3, null))); } }
测试结果再也不贴出。
注意:
注解Cacheable与Cacheput的区别:
cacheable通常用于查询数据,cacheput通常用于修改数据。二者都会对修饰的方法的返回值作缓存,若是在注解中没有指定缓存时的key而且也没有指定keyGenerator参数的话,那么默认key将会是直接调用缓存对象的toString()方法的返回值做为key,若是被修饰的方法没有返回值,那么缓存值value将会是null。
而且对于Cacheable若是在查询时发现缓存中存在,则再也不执行被修饰的方法体,也就是说不会取数据库中查询数据,而对于CachePut的话,无论怎样被修饰的方法体都会执行,因此说,Cacheable通常用于查询数据,而CachePut通常用于修改数据。
结果可测试获得,这里再也不贴出测试结果。
关于这三个注解的详细解释能够参考此篇博客:
http://blog.csdn.net/u012106290/article/details/52154367
关于EHCache配置文件中diskStore的解释可参看此篇博客: