前言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.ehcachegroupId> artifactId>ehcacheartifactId> version>2.10.2version> type>pomtype>dependency> 如果你的项目不使用maven管理,请在 Ehcache官网下载地址 下载jar包。 Spring 如果你的项目使用maven管理,添加以下依赖到你的pom.xml中。
dependency> groupId>org.springframeworkgroupId> artifactId>spring-context-supportartifactId> version>4.1.4.RELEASEversion>dependency> Ehcache的使用HelloWorld范例接触一种技术最快最直接的途径总是一个Hello World例子,毕竟动手实践印象更深刻,不是吗? (1) 在classpath下添加ehcache.xml 添加一个名为helloworld的缓存。 <>xml version='1.0' encoding='UTF-8'?>ehcache xmlns:xsi='http://www./2001/XMLSchema-instance' xsi:noNamespaceSchemaLocation='http:///ehcache.xsd'> diskStore path='java.io.tmpdir/ehcache'/> defaultCache maxEntriesLocalHeap='10000' eternal='false' timeToIdleSeconds='120' timeToLiveSeconds='120' maxEntriesLocalDisk='10000000' diskExpiryThreadIntervalSeconds='120' memoryStoreEvictionPolicy='LRU'/> cache name='helloworld' maxElementsInMemory='1000' eternal='false' timeToIdleSeconds='5' timeToLiveSeconds='5' overflowToDisk='false' memoryStoreEvictionPolicy='LRU'/>ehcache> (2) EhcacheDemo.java Ehcache会自动加载classpath根目录下名为ehcache.xml文件。 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基本操作
创建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();} 添加缓存需要强调一点, 使用CacheManager的addCache方法可以根据缓存名将ehcache.xml中声明的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); 删除缓存删除缓存比较简单,你只需要将指定的缓存名传入 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的 ehcache.xml配置参数说明:
ehcache.xml的一个范例 <>xml version='1.0' encoding='UTF-8'?>ehcache xmlns:xsi='http://www./2001/XMLSchema-instance' xsi:noNamespaceSchemaLocation='http:///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); 也可以通过 Cache cache = manager.getCache('sampleCache'); cache.disableDynamicFeatures(); Spring整合EhcacheSpring3.1开始添加了对缓存的支持。和事务功能的支持方式类似,缓存抽象允许底层使用不同的缓存解决方案来进行整合。 注:我本人使用的Spring版本为4.1.4.RELEASE,目前Spring版本仅支持Ehcache2.5以上版本,但不支持Ehcache3。 绑定Ehcache
spring-ehcache.xml的配置 <>xml version='1.0' encoding='UTF-8'?>beans xmlns='http://www./schema/beans' xmlns:xsi='http://www./2001/XMLSchema-instance' xmlns:cache='http://www./schema/cache' xsi:schemaLocation='http://www./schema/beanshttp://www./schema/beans/spring-beans-3.0.xsdhttp://www./schema/cache http://www./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-manager='cacheManager'/> (2) 使用标记注解 你也可以通过对一个类进行注解修饰的方式在这个类中使用缓存注解。 范例如下: @Configuration@EnableCachingpublic class AppConfig {} 注解基本使用方法Spring对缓存的支持类似于对事务的支持。 首先使用注解标记方法,相当于定义了切点,然后使用Aop技术在这个方法的调用前、调用后获取方法的入参和返回值,进而实现了缓存的逻辑。 下面三个注解都是方法级别: @Cacheable表明所修饰的方法是可以缓存的:当第一次调用这个方法时,它的结果会被缓存下来,在缓存的有效时间内,以后访问这个方法都直接返回缓存结果,不再执行方法中的代码段。 这个注解可以用 可以使用 @CachePut与 @CacheEvict与 @Servicepublic class UserService { // @Cacheable可以设置多个缓存,形式如:@Cacheable({'books', 'isbns'}) @Cacheable({'users'}) public User findUser(User user) { return findUserInDB(user.getId()); } @Cacheable(value = 'users', condition = '#user.getId() <=>=>) 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如果需要使用同一个缓存注解( @Caching(evict = { @CacheEvict('primary'), @CacheEvict(cacheNames='secondary', key='#p0') })public Book importBooks(String deposit, Date date) @CacheConfig与前面的缓存注解不同,这是一个类级别的注解。 @CacheConfig('books')public class BookRepositoryImpl implements BookRepository { @Cacheable public Book findBook(ISBN isbn) {...}} 参考如果想参考我的完整代码示例,请点击这里访问我的github。 下面是我在写作时参考的资料或文章。 |
|