概述
Spring 3.1 引入了激动人心的基于注释(annotation)的缓存(cache)技术,它本质上不是一个具体的缓存实现方案(例如 EHCache 或者OSCache),而是一个对缓存使用的抽象,通过在既有代码中添加少量它定义的各种 annotation,即能够达到缓存方法的返回对象的效果。
缓存的注解有以下三个
@Cancheable@CancheEvict @CachePut
引用缓存
package cacheOfAnno;
importorg.springframework.cache.annotation.CacheEvict;
importorg.springframework.cache.annotation.Cacheable;
public class AccountService {
@Cacheable(value="accountCache")// 使用了一个缓存名叫 accountCache
public Account getAccountByName(StringuserName) {
// 方法内部实现不考虑缓存逻辑,直接实现业务
System.out.println("real queryaccount."+userName);
return getFromDB(userName);
}
private Account getFromDB(String acctName) {
System.out.println("real queryingdb..."+acctName);
return new Account(acctName);
}
}
注意,此类的getAccountByName 方法上有一个注释 annotation,即 @Cacheable(value=”accountCache”),这个注释的意思是,当调用这个方法的时候,会从一个名叫 accountCache 的缓存中查询,如果没有,则执行实际的方法(即查询数据库),并将执行的结果存入缓存中,否则返回缓存中的对象。这里的缓存中的 key 就是参数userName,value 就是Account 对象。“accountCache”缓存是在 spring*.xml 中定义的名称。
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:p="http://www.springframework.org/schema/p"
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">
<cache:annotation-driven />
<bean id="accountServiceBean"class="cacheOfAnno.AccountService"/>
<!-- generic cache manager -->
<bean id="cacheManager"
class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean
class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean"
p:name="default" />
<bean
class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean"
p:name="accountCache"/>
</set>
</property>
</bean>
</beans>
清空缓存
有了缓存的实现,我们还得清空缓存
为了加入清空缓存的逻辑,我们只要对 AccountService.java 进行修改,从业务逻辑的角度上看,它有两个需要清空缓存的地方
当外部调用更新了账号,则我们需要更新此账号对应的缓存
当外部调用说明重新加载,则我们需要清空所有缓存
package cacheOfAnno;
importorg.springframework.cache.annotation.CacheEvict;
importorg.springframework.cache.annotation.Cacheable;
public class AccountService {
@Cacheable(value="accountCache")//使用了一个缓存名叫 accountCache
public Account getAccountByName(StringuserName) {
// 方法内部实现不考虑缓存逻辑,直接实现业务
return getFromDB(userName);
}
@CacheEvict(value="accountCache",key="#account.getName()")//清空 accountCache 缓存
public void updateAccount(Account account) {
updateDB(account);
}
@CacheEvict(value="accountCache",allEntries=true)// 清空 accountCache 缓存
public void reload() {
}
private Account getFromDB(String acctName) {
System.out.println("real queryingdb..."+acctName);
return new Account(acctName);
}
private void updateDB(Account account) {
System.out.println("real updatedb..."+account.getName());
}
}
按条件操作缓存
前面介绍的缓存方法,没有任何条件,即所有对 accountService 对象的 getAccountByName方法的调用都会起动缓存效果,不管参数是什么值,如果有一个需求,就是只有账号名称的长度小于等于 4 的情况下,才做缓存,大于 4 的不使用缓存,那怎么实现呢?
Springcache 提供了一个很好的方法,那就是基于 SpEL 表达式的 condition 定义,这个condition 是 @Cacheable 注释的一个属性,下面我来演示一下
AccountService.java(getAccountByName方法修订,支持条件)
@Cacheable(value="accountCache",condition="#userName.length()<= 4")// 缓存名叫 accountCache
public Account getAccountByName(StringuserName) {
// 方法内部实现不考虑缓存逻辑,直接实现业务
return getFromDB(userName);
}
其中的 condition=”#userName.length() <=4”,这里使用了 SpEL 表达式访问了参数 userName对象的 length() 方法,条件表达式返回一个布尔值,true/false,当条件为 true,则进行缓存操作,否则直接调用方法执行的返回结果
小结:
注解驱动能极大减少我们编写常见缓存代码量,通过少量标签和配置文件,可达到代码具备缓存的效果,灵活性很好。