原文地址 http://jinnianshilongnian.iteye.com/blog/2001040
@CachePut
应用到写数据的方法上,如新增/修改方法,调用方法时会自动把相应的数据放入缓存:
- @CachePut(value = "user", key = "#user.id")
- public User save(User user) {
- users.add(user);
- return user;
- }
即调用该方法时,会把user.id作为key,返回值作为value放入缓存;
@CachePut注解:
- public @interface CachePut {
- String[] value(); //缓存的名字,可以把数据写到多个缓存
- String key() default ""; //缓存key,如果不指定将使用默认的KeyGenerator生成,后边介绍
- String condition() default ""; //满足缓存条件的数据才会放入缓存,condition在调用方法之前和之后都会判断
- String unless() default ""; //用于否决缓存更新的,不像condition,该表达只在方法执行之后判断,此时可以拿到返回值result进行判断了
- }
@CacheEvict
即应用到移除数据的方法上,如删除方法,调用方法时会从缓存中移除相应的数据:
- @CacheEvict(value = "user", key = "#user.id") //移除指定key的数据
- public User delete(User user) {
- users.remove(user);
- return user;
- }
- @CacheEvict(value = "user", allEntries = true) //移除所有数据
- public void deleteAll() {
- users.clear();
- }
@CacheEvict注解:
- public @interface CacheEvict {
- String[] value(); //请参考@CachePut
- String key() default ""; //请参考@CachePut
- String condition() default ""; //请参考@CachePut
- boolean allEntries() default false; //是否移除所有数据
- boolean beforeInvocation() default false;//是调用方法之前移除/还是调用之后移除
@Cacheable
应用到读取数据的方法上,即可缓存的方法,如查找方法:先从缓存中读取,如果没有再调用方法获取数据,然后把数据添加到缓存中:
- @Cacheable(value = "user", key = "#id")
- public User findById(final Long id) {
- System.out.println("cache miss, invoke find by id, id:" + id);
- for (User user : users) {
- if (user.getId().equals(id)) {
- return user;
- }
- }
- return null;
- }
@Cacheable注解:
- public @interface Cacheable {
- String[] value(); //请参考@CachePut
- String key() default ""; //请参考@CachePut
- String condition() default "";//请参考@CachePut
- String unless() default ""; //请参考@CachePut
运行流程
- 1、首先执行@CacheEvict(如果beforeInvocation=true且condition 通过),如果allEntries=true,则清空所有
- 2、接着收集@Cacheable(如果condition 通过,且key对应的数据不在缓存),放入cachePutRequests(也就是说如果cachePutRequests为空,则数据在缓存中)
- 3、如果cachePutRequests为空且没有@CachePut操作,那么将查找@Cacheable的缓存,否则result=缓存数据(也就是说只要当没有cache put请求时才会查找缓存)
- 4、如果没有找到缓存,那么调用实际的API,把结果放入result
- 5、如果有@CachePut操作(如果condition 通过),那么放入cachePutRequests
- 6、执行cachePutRequests,将数据写入缓存(unless为空或者unless解析结果为false);
- 7、执行@CacheEvict(如果beforeInvocation=false 且 condition 通过),如果allEntries=true,则清空所有
流程中需要注意的就是2/3/4步:
如果有@CachePut操作,即使有@Cacheable也不会从缓存中读取;问题很明显,如果要混合多个注解使用,不能组合使用@CachePut和@Cacheable;官方说应该避免这样使用(解释是如果带条件的注解相互排除的场景);不过个人感觉还是不要考虑这个好,让用户来决定如何使用,否则一会介绍的场景不能满足。