Welcome 微信登录

首页 / 软件开发 / JAVA / 注释驱动的Spring cache缓存介绍

注释驱动的Spring cache缓存介绍2013-09-18 IBM 赵才文概述

Spring 3.1 引入了激动人心的基于注释(annotation)的缓存(cache)技术,它本质上不是一个具体的缓存实现方案 (例如 EHCache 或者 OSCache),而是一个对缓存使用的抽象,通过在既有代码中添加少量它定义的各种 annotation,即 能够达到缓存方法的返回对象的效果。

Spring 的缓存技术还具备相当的灵活性,不仅能够使用 SpEL(Spring Expression Language)来定义缓存的 key 和各种 condition,还提供开箱即用的缓存临时存储方案,也支持和主流的专业 缓存例如 EHCache 集成。

其特点总结如下:

通过少量的配置 annotation 注释即可使得既有代码支持缓存

支持开箱即用 Out-Of-The-Box,即不用安装和部署额外第三方组件即可使用缓存

支持 Spring Express Language,能使用对象的任何属性或者方法来定义缓存的 key 和 condition

支持 AspectJ,并通过其实现任何方法的缓存支持

支持自定义 key 和自定义缓存管理者,具有相当的灵活性和扩展性

本文将针对上述特点对 Spring cache 进行详细的介绍,主要通过一个简单的例子和原理介绍展开,然后我们将一起看 一个比较实际的缓存例子,最后会介绍 spring cache 的使用限制和注意事项。OK,Let ’ s begin!

原来我们是怎 么做的

这里先展示一个完全自定义的缓存实现,即不用任何第三方的组件来实现某种对象的内存缓存。

场景是:对一个 账号查询方法做缓存,以账号名称为 key,账号对象为 value,当以相同的账号名称查询账号的时候,直接从缓存中返回结 果,否则更新缓存。账号查询服务还支持 reload 缓存(即清空缓存)。

首先定义一个实体类:账号类,具备基本 的 id 和 name 属性,且具备 getter 和 setter 方法

清单 1. Account.java

package cacheOfAnno; public class Account { private int id; private String name;public Account(String name) { 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; } }
然后定义一个缓存管理器,这个管理器负责实现缓存逻辑,支持对象的增加、修改和删除,支持值对象的泛型。 如下:

清单 2. MyCacheManager.java

package oldcache; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class MyCacheManager<T> { private Map<String,T> cache = new ConcurrentHashMap<String,T>();public T getValue(Object key) { return cache.get(key); }public void addOrUpdateCache(String key,T value) { cache.put(key, value); }public void evictCache(String key) {// 根据 key 来删除缓存中的一条记录if(cache.containsKey(key)) { cache.remove(key); } }public void evictCache() {// 清空缓存中的所有记录cache.clear(); } }
好,现在我们有了实体类和一个缓存管理器,还需要一个提供账号查询的服务类,此服务类使用缓存管理器来支 持账号查询缓存,如下:

清单 3. MyAccountService.java

package oldcache; import cacheOfAnno.Account; public class MyAccountService { private MyCacheManager<Account> cacheManager;public MyAccountService() { cacheManager = new MyCacheManager<Account>();// 构造一个缓存管理器}public Account getAccountByName(String acctName) { Account result = cacheManager.getValue(acctName);// 首先查询缓存if(result!=null) { System.out.println("get from cache..."+acctName); return result;// 如果在缓存中,则直接返回缓存的结果} result = getFromDB(acctName);// 否则到数据库中查询if(result!=null) {// 将数据库查询的结果更新到缓存中cacheManager.addOrUpdateCache(acctName, result); } return result; }public void reload() { cacheManager.evictCache(); }private Account getFromDB(String acctName) { System.out.println("real querying db..."+acctName); return new Account(acctName); } }