注:除了上述使用方法参数作为key之外,Spring还为我们提供了一个root对象可以用来生成key。通过该root对象我们可以获取到以下信息。
属性名称 |
描述 |
示例 |
methodName |
当前方法名 |
#root.methodName |
method |
当前方法 |
#root.method.name |
target |
当前被调用的对象 |
#root.target |
targetClass |
当前被调用的对象的class |
#root.targetClass |
args |
当前方法参数组成的数组 |
#root.args[0] |
caches |
当前被调用的方法使用的Cache |
#root.caches[0].name |
2.@CachePut
在支持Spring Cache的环境下,对于使用@Cacheable标注的方法,Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素,如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,否则才会执行并将返回结果存入指定的缓存中。@CachePut也可以声明一个方法支持缓存功能。与@Cacheable不同的是使用@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。
@CachePut也可以标注在类上和方法上。使用@CachePut时我们可以指定的属性跟@Cacheable是一样的。
3.@CacheEvict
@CacheEvict是用来标注在需要清除缓存元素的方法或类上的。当标记在一个类上时表示其中所有的方法的执行都会触发缓存的清除操作。@CacheEvict可以指定的属性有value、key、condition、allEntries和beforeInvocation。其中value、key和condition的语义与@Cacheable对应的属性类似。即value表示清除操作是发生在哪些Cache上的(对应Cache的名称);key表示需要清除的是哪个key,如未指定则会使用默认策略生成的key;condition表示清除操作发生的条件。下面我们来介绍一下新出现的两个属性allEntries和beforeInvocation。
allEntries:是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存。如:@CachEvict(value=”testcache”,allEntries=true)
beforeInvocation:是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存。如:@CachEvict(value=”testcache”,beforeInvocation=true)
其他参数和@Cacheable相同
4.@Caching
@Caching注解可以让我们在一个方法或者类上同时指定多个Spring Cache相关的注解。其拥有三个属性:cacheable、put和evict,分别用于指定@Cacheable、@CachePut和@CacheEvict。如: @Caching(cacheable = @Cacheable("users"), evict = { @CacheEvict("cache2"),@CacheEvict(value = "cache3", allEntries = true) })
二、实例
使用map集合实现缓存管理,演示spring cache的使用。
1.创建缓存对象实例
package org.springframework.cache.demo; import java.io.Serializable; //缓存对象 public class User implements Serializable{ /** * */ private static final long serialVersionUID = 1L; private int id; private String name; public User(){ } public User(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.对象服务实现类
package org.springframework.cache.demo; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; /** * 业务服务 * */ public class UserService { @Cacheable(value = "userCache",key="#userName") // 使用了一个缓存名叫 userCache public User getUserByName(String userName) { // 方法内部实现不考虑缓存逻辑,直接实现业务 return getFromDB(userName); } @CacheEvict(value = "userCache", key = "#user.name") // 清空 accountCache 缓存 public void updateUser(User user) { updateDB(user); } @CacheEvict(value = "userCache", allEntries = true,beforeInvocation=true) // 清空 accountCache 缓存 public void reload() { } private User getFromDB(String userName) { System.out.println("查询数据库..." + userName); return new User(userName); } private void updateDB(User user) { System.out.println("更新数据库数据..." + user.getName()); } }
3.缓存实现
package org.springframework.cache.demo.mycache; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.springframework.cache.Cache; import org.springframework.cache.support.SimpleValueWrapper; public class MyCache implements Cache { private String name; private Map<String, Object> store = new ConcurrentHashMap<String, Object>();; public MyCache() { } public MyCache(String name) { this.name = name; } public void setName(String name) { this.name = name; } public void clear() { store.clear(); } public void evict(Object obj) { } public ValueWrapper get(Object key) { ValueWrapper result = null; Object thevalue = store.get(key); if (thevalue != null) { result = new SimpleValueWrapper(thevalue); } return result; } public <T> T get(Object key, Class<T> clazz) { return clazz.cast(store.get(key)); } public String getName() { return name; } public Object getNativeCache() { return store; } public void put(Object key, Object value) { store.put((String) key, value); } public ValueWrapper putIfAbsent(Object key, Object value) { put(key, value); return new SimpleValueWrapper(value); } }4.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" 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"> <!-- 启用缓存注解功能,这个是必须的,否则注解不会生效,另外,该注解一定要声明在spring主配置文件中才会生效 --> <cache:annotation-driven cache-manager="cacheManager" /> <bean id="userService" class="org.springframework.cache.demo.UserService" /> <!-- generic cache manager --> <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager"> <property name="caches"> <set> <bean class="org.springframework.cache.demo.mycache.MyCache" p:name="userCache" /> </set> </property> </bean> </beans>5.运行类
package org.springframework.cache.demo.mycache; import org.springframework.cache.demo.User; import org.springframework.cache.demo.UserService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyMain { @SuppressWarnings("resource") public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("spring-cache-mycache.xml"); UserService userService = context.getBean(UserService.class); // 第一次查询,应该走数据库 System.out.print("第一次查询..."); userService.getUserByName("hello"); // 第二次查询,应该不查数据库,直接返回缓存的值 System.out.println("第二次查询..."); userService.getUserByName("hello"); System.out.println(); System.out.println("=============="); // 更新某个记录的缓存,首先构造两个用户记录,然后记录到缓存中 User user1 = userService.getUserByName("user1"); // 开始更新其中一个 user1.setId(1000); userService.updateUser(user1); // 因为被更新了,所以会查询数据库 userService.getUserByName("user1"); // 再次查询,应该走缓存 userService.getUserByName("user1"); // 更新所有缓存 userService.reload(); System.out.println("清楚所有缓存"); // 查询数据库 userService.getUserByName("user1"); userService.getUserByName("user2"); // 查询缓存 userService.getUserByName("user1"); userService.getUserByName("user2"); } }运行结果:
第一次查询...查询数据库...hello 第二次查询... ============== 查询数据库...user1 更新数据库数据...user1 清楚所有缓存 查询数据库...user1 查询数据库...user2
参考文档:
1.Spring Cache抽象详解
2.Spring使用Cache、整合Ehcache
3.注释驱动的 Spring cache 缓存介绍