springboot 之缓存注解

今天介绍如何使用springboot的注解来缓存一个Object 或者一个List 列表。

1:  引入 maven 依赖   使用 springboot  2.1.3.RELEASE

<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

 

2: 配置使用 ehcache 

a476ebcf69ba946ceeeec5caf1bda45bfe1.jpg

 

spring.cache.type=ehcache
spring.cache.ehcache.config=classpath:/ehcache.xml

 

3: 配置 ehcache 

在项目的根目录添加 ehcache.xml , 

<ehcache>

    <!--
        磁盘存储:将缓存中暂时不使用的对象,转移到硬盘,类似于Windows系统的虚拟内存
        path:指定在硬盘上存储对象的路径
        path可以配置的目录有:
            user.home(用户的家目录)
            user.dir(用户当前的工作目录)
            java.io.tmpdir(默认的临时目录)
            ehcache.disk.store.dir(ehcache的配置目录)
            绝对路径(如:d:\\ehcache)
        查看路径方法:String tmpDir = System.getProperty("java.io.tmpdir");
     -->
    <diskStore path="java.io.tmpdir" />

    <!--
        defaultCache:默认的缓存配置信息,如果不加特殊说明,则所有对象按照此配置项处理
        maxElementsInMemory:设置了缓存的上限,最多存储多少个记录对象
        eternal:代表对象是否永不过期 (指定true则下面两项配置需为0无限期)
        timeToIdleSeconds:最大的发呆时间 /秒
        timeToLiveSeconds:最大的存活时间 /秒
        overflowToDisk:是否允许对象被写入到磁盘
        说明:下列配置自缓存建立起600秒(10分钟)有效 。
        在有效的600秒(10分钟)内,如果连续120秒(2分钟)未访问缓存,则缓存失效。
        就算有访问,也只会存活600秒。
     -->
    <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="600" timeToLiveSeconds="600" overflowToDisk="true" />

    <cache name="tenMin" maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="600" overflowToDisk="true" />
    <cache name="quarter" maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="900" overflowToDisk="true" />
    <cache name="halfHour" maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="1800" overflowToDisk="true" />
    <cache name="oneHour" maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="3600" overflowToDisk="true" />
    <cache name="halfDay" maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="43200" overflowToDisk="true" />
    <cache name="oneDay" maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="86400" overflowToDisk="true" />
</ehcache>

 

4: springboot 开启缓存注解的功能。 

c396d06598a6eaa3dc674c6f77d70587f83.jpg 

 

5:  使用 @Cacheable 进行缓存,  将搜索列表的结果缓存10分钟。

500c598e290e1817381d0da0e4238296e94.jpg

 

 

6: 如何测试缓存生效了? 在方法中打一个断点, 第一次访问触发到断点了, 第二次访问没有触发断点,  两分钟后再访问又触发了断点。 

 

7: 如何更新缓存?  数据库的数据会有增加,删除和修改, 会导致和缓存中的数据不一致.   

    从A机器搜索关键词可能命中10条记录,但由于数据库变更会导致下次在B 机器上搜索相同的关键词可能命中11条数据。  A 和 B 两台机器上的缓存不一致。 还有就是删除记录就是 10分之后才会删除,如果能忍受这些。

 

      

8:缓存的效率问题     

1: 如果2分钟之内这个列表只被访问1次,那么这个缓存就是个累赘,白白消耗内存。  因此缓存的列表一定得是高频使访问的。 

2:重复缓存的问题。 假设2分钟内有效的搜索词为n, 每次搜索用户会点击前两页 ,那么会产生 2n个 list, 2n * 10 个 Object,   其中有些Object 必定是被多次重复缓存的。 

 

9: Redis 和 Ehcache 之争。    如果网站本身没有多少并发访问的使用Ehcache ,甚至可以不使用缓存,只要数据库能抗, 数据库扛不住加Ehcache, Ehcache 扛不住再想其他办法, 如果到了Ehcache 都扛不住那就是这个网站已经比较成功了,可以考虑请个高人进行开发。 

 

 10 :  spring缓存和Hibernate缓存                           

        网上一般介绍 Hibernate 缓存有两级缓存 1 : 一级缓存, session 级别的缓存  2: 二级缓存 factory 层级的缓存,亦称进程级别或者应用级别的缓存。 个人理解  springboot的缓存是可以完全替代Hibernate的二级缓存的。

 

 

总结  springboot 的骚操作比较多,比较简单, 相比于spring 复杂的xml 配置, springboot 的配置则大大简化,更加易于初级程序员上手使用,从而提高了开发的效率和质量,减少了程序员的代码量。 Pivotal 是一家纯粹靠技术起家的公司。 

 

 

原理分析:  debug 跟踪堆栈信息是比较靠谱的逆向分析方法。 顺向思维就是去看源码,读懂源码的每一步操作,但是读懂源码却是十分十分的困难,难于上青天。

堆栈信息如下:   

d50a81876424b505a7720980e90a4de8ee4.jpg

 

先是执行了  AreaController$$EnhancerBySpringCGLIB 的 getContent 方法 , 此getContent 是重写了 AreaController 的getContent 方法, 

然后执行了一些列的拦截器  

 CglibAopProxy$DynamicAdvisedInterceptor  ---> ExposeInvocationInterceptor  --------------->DruidStatInterceptor ------------> CacheInterceptor ------> AreaController$$FastClassBySpringCGLIB  

执行了这么多才会调用我们写的 method getContent 。 

 

具体的实现在   CacheAspectSupport 类里面 。   

ef064b344d272f173904a3d19ccae1b8b67.jpg

 

在这里也能略微体会到 filter 和 interceptor 的区别。

filter01--------->filter02--------> filter03 -----> controller(method)-----------> response         filter 是单向的执行,无法获取到method的返回值。

interceptor01  ------> interceptor02     -------->  controller(method)    ------->  interceptor02  --------->interceptor01 

interceptor 的执行却类似一个U, 是可以获取到method的返回值的。 filter 能干的事 interceptor 一定能干, 并且interceptor 可以干 filter 干不了的事。

 

关于chain , 责任链是一种JAVA 设计模式。 在我所接触的软件中,我知道这些地方使用到了责任链模式。 

1:  tomcat  的 Value 链

 网上分析的文章不多,毕竟研究servlet容器的工程师少,只有那些闲得无聊的人才会去看servlet容器是如何运转的。  这篇博客也有提及 https://my.oschina.net/qidis/blog/1154580

2: Servlet 的 FilterChain    

 相信从事过javaweb 开始的工程师都应该了解这个,网上关于过滤链的分析非常多。 

3: 再加上 spring 的 拦截器链。

 

 

 

AreaController$$EnhancerBySpringCGLIB  和   AreaController$$FastClassBySpringCGLIB   值得分析一下,前者是spring 的大BOSS,我们写的Controller , Service ,Repository  都被 EnhancerBySpringCGLIB 代理了。 有了这层代理后, spring 在执行我们写的方法的前后植入了相关的功能,执行之前先执行拦截器,执行之后执行渲染操作。

 

 

 

 

 

 

 

 

 

 


 

 

 

 

 

转载于:https://my.oschina.net/qidis/blog/3052382

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值