Spring实战——缓存
缓存
提到缓存,你能想到什么?一级缓存,二级缓存,web缓存,redis……
你所能想到的各种包罗万象存在的打着缓存旗号存在的各种技术或者实现,无非都是宣扬缓存技术的优势就是快,无需反复查询等。
当然,这里要讲的不是一级二级,也不是redis,而是Spring的缓存支持。当时基于工作上的业务场景,考虑需要用到缓存技术,但是并不清楚该用什么样的缓存技术,起初甚至有想过把信息写到redis中,然后读redis的信息(现在想想,真是小题大做),后来发现Spring提供了缓存的解决方案——Spring Cache。虽然最终找到了一个更加简便讨巧的方式解决了问题,但是今天还是把自己零碎的Spring Cache知识稍稍梳理下。
这里大概介绍下业务场景:
- 现在有功能模块一和功能模块二,分别负责两件事;
- 执行功能模块二的时候,可以用到模块一的执行结果,当然不用也可以,那就再执行一遍;
- 读取功能模块一执行后存放在Cache中的数据,这时候就省去重新执行模块一的冗余操作
流程图如下:
Spring Cache
有关Spring Cache的理论详细介绍可以看官方文档或者参阅《Spring实战》第十三章,这里偏代码实战看看Spring Cache如何使用。
声明启用缓存
就像如果要启用AOP需要添加
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
一样,如果要用cache,也需要声明
<cache:annotation-driven />
这样还不够,除此以外,我们还需要一个缓存管理器
<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="personCache" />
</set>
</property>
</bean>
这个缓存管理器是Spring缓存抽象的核心,可以继承多个流行的缓存实现。从上面的声明可以看出,这里声明了ConcurrentMapCacheManager
管理器,从字面就可以看出其内容实现应该是通过ConcurrentHashMap
来做缓存的。(除了这个简单的缓存管理器,当然还有如NoOpCacheManager、EhCacheCacheManager、RedisCacheManager、CompositeCacheManager等管理器)
这里的personCache
就是本例中用到的声明的管理器
以上的xml声明可以存放到一个spring-cache.xml中,完整内容如下
<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">
<cache:annotation-driven />
<bean id="personService" class="com.jackie.service.PersonService" />
<!-- 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="personCache" />
</set>
</property>
</bean>
</beans>
编写需要缓存的方法
- 在此之前,我们需要一个bean对象Person,其有
id
,age
,name
三个属性
@Component
public class Person {
private int id;
private int age;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
}
- 准备需要缓存的接口方法
@Service("personService")
public class PersonService {
@Cacheable(value = "personCache")
public Person findPerson(int i) {
System.out.println("real query person object info");
Person person = new Person();
person.setId(i);
person.setAge(18);
person.setName("Jackie");
return person;
}
}
findPerson()
方法很简单,主要是根据id查找到相应的Person对象。
这里第一行加上了打印信息,用于区分每次调用是否走缓存了。如果直接用的是缓存结果,则不会打印这句话,如果没有缓存,则需要执行函数体,从而打印改行显示。
@Cacheable
注解:主要用来配置方法,能够根据方法的请求参数对其结果进行缓存。即当重复使用相同参数调用方法的时候,方法本身不会被调用执行,即方法本身被略过了,取而代之的是方法的结果直接从缓存中找到并返回了。简而言之就是如果缓存有则取出,如果没有则执行方法。
验证
到此我们就可以验证了。编写代码如下
public class SpringCache {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"spring-cache.xml");// 加载 spring 配置文件
PersonService personService = (PersonService) context.getBean("personService");
// 第一次查询,应该真实查询
System.out.println(personService.findPerson(18));
// 第二次查询,应该直接返回缓存的值
System.out.println(personService.findPerson(18));
}
}
最终执行结果如下
real query person object info
Person{id=18, age=18, name='Jackie'}
Person{id=18, age=18, name='Jackie'}
可以看出第一次结果显示前打印出了real query person object info
说明真实执行了findPerson()
方法;
第二次打印的结果没有包含这行信息,说明是从缓存中直接取的数据,而且通过调试打断点确实发现第二次并未进入findPerson()
方法。
@CacheEvict
之所以能够不用执行方法直接拿到缓存结果,是因为将执行结果存到了缓存中。既然有存缓存的过程,自然有删除缓存的过程,而这个操作就要用到@CacheEvict
这个注解了。
还是通过实例来看,这里举出两个例子——根据方法清除缓存和清除全部缓存。
我们在PersonService中分别加上这两个接口方法
@CacheEvict(value = "personCache", key = "#person.getId()")
public void updatePerson(Person person) {
System.out.println("update: " + person.getName());
}
@CacheEvict(value = "personCache", allEntries = true)
public void reload() {
}
稍稍解释下,当updatePerson()
方法被调用时,其会根据key来取出相应的缓存记录删除;而对于方法reload()
则是在该方法被调用时,清空所有缓存记录。
测试代码如下
Person lucy = personService.findPerson(1);
Person lily = personService.findPerson(2);
lucy.setName("Tracy");
personService.updatePerson(lucy);
System.out.println(personService.findPerson(1));
System.out.println(personService.findPerson(2));
personService.reload();
System.out.println(personService.findPerson(1));
System.out.println(personService.findPerson(2));
执行结果如下
real query person object info
real query person object info
update: Tracy
real query person object info
Person{id=1, age=18, name='Jackie'}
Person{id=2, age=18, name='Jackie'}
real query person object info
Person{id=1, age=18, name='Jackie'}
real query person object info
Person{id=2, age=18, name='Jackie'}
第1,2行分别是因为针对id=1,2都是第一次查询,这时候没有缓存记录,所以都真实执行了方法findPerson()
;
第3行是调用方法updatePerson()
打印的信息
第4,5行是再次查询id=1的Person信息,这里之所以打印出real query person object info
是因为之前调用了id=1时的updatePerson()
方法,该方法触发,根据getId()
找到id=1的缓存记录进行删除,所以这时候查找id=1的时候,缓存记录已经不存在,故而要执行findPerson()
方法。
第6行是再次查询id=2的Person信息,因为之前已经查过一次,并且没有删除过这条缓存记录,所以再次查找时,直接用缓存结果。
第7,8行是再次查询id=1的Person信息,注意再次之前,执行了reload()
方法,这个方法会清楚所有的缓存信息,所以对于id=1和2的缓存记录都已经清空,这里就又重新执行findPerson()
方法
第9,10行同7,8
当然,关于Spring Cache还有很多灵活的应用以及功能强大的注解和用法,这里只是通过实例了解Spring Cache有什么用,如何用。
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!如果您想持续关注我的文章,请扫描二维码,关注JackieZheng的微信公众号,我会将我的文章推送给您,并和您一起分享我日常阅读过的优质文章。
Spring实战——缓存的更多相关文章
- Spring 对缓存的抽象
Cache vs. Buffer A buffer is used traditionally as an intermediate temporary store for data between ...
- 【Spring实战】----开篇(包含系列目录链接)
[Spring实战]----开篇(包含系列目录链接) 置顶2016年11月10日 11:12:56 阅读数:3617 终于还是要对Spring进行解剖,接下来Spring实战篇系列会以应用了Sprin ...
- Spring实战(第4版).pdf - 百度云资源
http://www.supan.vip/spring%E5%AE%9E%E6%88%98 Spring实战(第4版).pdf 关于本书 Spring框架是以简化Java EE应用程序的开发为目标而创 ...
- 注释驱动的 Spring cache 缓存介绍
概述 Spring 3.1 引入了激动人心的基于注释(annotation)的缓存(cache)技术,它本质上不是一个具体的缓存实现方案(例如 EHCache 或者 OSCache),而是一个对缓存使 ...
- [转]注释驱动的 Spring cache 缓存介绍
原文:http://www.ibm.com/developerworks/cn/opensource/os-cn-spring-cache/ 概述 Spring 3.1 引入了激动人心的基于注释(an ...
- spring实战五之Bean的自动检测
在spring实战四中,使用在Spring中增加<context:annotation-config>的方式告诉Spring,我们打算使用基于注解的自动装配,希望Spring特殊对待我们所 ...
- Spring实战6:利用Spring和JDBC访问数据库
主要内容 定义Spring的数据访问支持 配置数据库资源 使用Spring提供的JDBC模板 写在前面:经过上一篇文章的学习,我们掌握了如何写web应用的控制器层,不过由于只定义了SpitterRep ...
- Spring实战——无需一行xml配置实现自动化注入
已经想不起来上一次买技术相关的书是什么时候了,一直以来都习惯性的下载一份电子档看看.显然,如果不是基于强烈的需求或强大的动力鞭策下,大部分的书籍也都只是蜻蜓点水,浮光掠影. 就像有位同事说的一样,有些 ...
- 注释驱动的 Spring cache 缓存介绍--转载
概述 Spring 3.1 引入了激动人心的基于注释(annotation)的缓存(cache)技术,它本质上不是一个具体的缓存实现方案(例如 EHCache 或者 OSCache),而是一个对缓存使 ...
随机推荐
- Java日常总结之LinkedList、ArrayList的效率分析
前言: 在我们平常开发中难免会用到List集合来存储数据,一般都会选择ArrayList和LinkedList,以前只是大致知道ArrayList查询效率高LinkedList插入删除效率高,今天来实 ...
- hadoop2.7.2完全分布式环境搭建
1.先使用groupadd hadoop 建立hadoop用户组 2.新建用户,useradd -d /usr/hadoop -g hadoop -m hadoop (新建用户hadoop指定用户 ...
- spring提供的线程池
SPRING中的线程池ThreadPoolTaskExecutor 分类: JAVA Spring2013-07-12 10:36 14896人阅读 评论(9) 收藏 举报 Spring线程池多线程 ...
- 深究WeixinJSBridge未定义之因
对于一个没有使用微信JS-SDK的网站来说,我们竟然收到了WeixinJSBridge is not defined 的报错: 去网上一搜,发现很多开发者都遇到类似的问题: 我的微信项目,没有用到微信 ...
- ES3:ElasticSearch 索引
ElasticSearch是文档型数据库,索引(Index)定义了文档的逻辑存储和字段类型,每个索引可以包含多个文档类型,文档类型是文档的集合,文档以索引定义的逻辑存储模型,比如,指定分片和副本的数量 ...
- SEO-关键词密度与友情链接交换技巧
关键词密度 关键词密度 关键词密度与关键词频率所阐述的实质上是同一个概念,用来量度关键词在网页上出现的总次数与其他文字的比例,一般用百分比表示.相对于页面总字数而言,关键词出现的频率越高,关键词密度也 ...
- Omi v1.0震撼发布 - 令人窒息的Web组件化框架
原文链接--https://github.com/AlloyTeam/omi 写在前面 Omi框架经过几十个版本的迭代,越来越简便易用和强大. 经过周末的连续通宵加班加点,Omi v1.0版本终于问世 ...
- 读书笔记 effective c++ Item 34 区分接口继承和实现继承
看上去最为简单的(public)继承的概念由两个单独部分组成:函数接口的继承和函数模板继承.这两种继承之间的区别同本书介绍部分讨论的函数声明和函数定义之间的区别完全对应. 1. 类函数的三种实现 作为 ...
- Android Studio开发遇到程序崩溃问题
在用Android Studio开发过程中,经常遇到程序本身没有错误,但运行起来却总是挂掉,具体有如下几个解决方案: 1.将运行在真机上的app卸载,重新运行安装 2.在Build选项中有一个clea ...
- 用webstorm自动编译less产出css和sourcemap
css产出sourcemap有什么用呢,可能大家要问这个问题了. 请移步这里 https://developers.google.com/chrome-developer-tools/docs/css ...