Springboot中的缓存Cache和CacheManager原理介绍

背景理解

什么是缓存,为何要用缓存

程序运行中,在内存保持必定时间不变的数据就是缓存。简单到写一个Map,里面放着一些key,value数据,就已是个缓存了html

因此缓存并非什么高大上的技术,只是个概念,把要屡次使用的东西存在一个变量里,时不时取出来使用,就达到了缓存的目的,缓存就是存放数据的容器java

那为何要用缓存呢,是由于要屡次使用。一个程序总有一些数据时可预见被屡次使用(预见的准不许就是常说的命中率)redis

好比一个复杂的计算结果,一次数据库访问取得的数据等耗时耗资源的数据就能放入缓存,目的就是为了节省开销,咱们要用有限的资源(CPU,内存,带宽等等)尽可能作最多的事情。数据库

为何要用SpringCache(缓存的演变过程)

缓存的思考

若是咱们要设计一个缓存,最基本的功能是存和取:缓存

1.能在缓存里存放数据安全

2.能在缓存里取出数据工具

但是这不够呀,好比如下的思考学习

1.取数据时判断,数据是否存在,若是不存在是否是要数据库取spa

2.若是是过时的内容是否是要更新设计

3.若是我有多个缓存,一个是我本身设计的HashMap缓存,一个是名声很大的redis,还有....,那须要个缓存管理器呀

为了让缓存更好用,更“智能”,愈来愈多的需求就会被提出来,而缓存就是这样一步步演变直到SpringCache横空出世,功能十分强大(说白了就是咱们少写不少代码)

SpringCache的好处

SpringCache包含两个顶级接口,Cache(缓存)和CacheManager(缓存管理器),顾名思义,用CacheManager去管理一堆Cache。

最最关键的地方:抱紧了Spring的大腿,可使用注解就能完成数据进入缓存!!

给你们举个例子,就知道多简单了

首先,Springboot中会自动加载一个CacheManager(它有默认的实现类),因此只要写好一个自定义的Cache便可(若是想用系统定义好的或者第三方如RedisCache也行,记得向Spring注册这个bean便可)

@Component
public class MyCache implements Cache {
  /*
       实现接口方法,一些关于数据set和get的方法
       CacheManager是根据Cache的名字进行管理的
       因此假设这个Cache名为MyCache
  */  
}

而后在得出数据的方法上写上注释便可

@Cacheable(value = "MyCache",key = "#id")
public String getNavegationURLs(String id) {
        //一个获取数据的方法
}

这样就会在调用这个方法时,会以id为key值,在名为MyCache的Cache容器中查找(注解中value就是缓存名字,不一样名字指定使用不一样的缓存)

若是没查到,则执行方法 getNavegationURLs,将返回值存入缓存

若是找到了,就直接将从缓存取值,直接返回,不用执行方法 getNavegationURLs

还有其余方便的Cache注解自行百度,重要的是咱们根本不用写任何关于调用缓存的逻辑代码,只用关注于缓存自身的逻辑

注解如何起做用的,源码流程大体了解

为何要了解源码

最直接的缘由是由于SpringCache是不支持灵活的缓存时间设置的,因此想了解大概的前因后果去实现一个支持缓存过时时间设置和自动更新的类(以后会写实现博文)。

高大上的缘由是想经过此次探索,去了解下Spring对类的管理机制,去接触下AOP的实现

SpringCache源码简单分析

你们从上面例子有没发现问题,Cache和CacheManager是怎样作关联的,实际上是Spring扫包实现的

凡是继承了Cache接口的类,都会被自动注入进CacheManager中,最终存储于CacheManager的实现类中

 

 接着会生成被@Cacheable(或者其余SpringCache注解修饰过)的代理类,并会将管理它的CacheManager赋值进去

 看这段代码,就知道若是要设置多个CacheManager,就得在众多实现类的其中一个加上@Primary,否则会Spring会报错能选择的Bean太多而不知道用哪一个

 

代理类生成后(包括会根据不一样的注解生成信息类CacheOperationMetadata,到时候就会根据这个类的内容进行缓存操做,说白了就是调用咱们实现Cache里面的各类方法)

Springboot底层初始化完成后,进入咱们写的代码逻辑

若是这时进入了该类的方法,如:

 

 代码跟进去,你会神奇的发现进入了代理类的intercept方法,怎么进去的呢~(具体原理看下面3.0)

 这里面就会根据注解类型,进行缓存的逻辑判断,而后决定会不会调用咱们写的方法~

 代理类原理介绍(AOP切面之类的都是经过代理哦)

Spring代理分为两种:

1.JDK原生动态代理,要求被代理的类须要实现接口(经过接口来实现的代理

那么代理类知足如下条件:

首先实现一个InvocationHandler,方法调用会被转发到该类的invoke()方法。
意思是:对代理对象的全部接口方法调用都会转发到InvocationHandler.invoke()方法,在invoke()方法里咱们能够加入任何逻辑,好比修改方法参数,加入日志功能、安全检查功能等;以后咱们经过某种方式执行真正的方法体
 
2.CGLIB动态代理,不要求被代理的类须要实现接口,可是final的方法没法被代理( 经过继承来实现代理
那么代理类知足如下条件:
实现一个MethodInterceptor,方法调用会被转发到该类的intercept()方法

具体内容能够参考这篇精品博客:http://www.javashuo.com/article/p-wtdaezwq-ke.html

若是你想本身实现代理类(就是不喜欢用工具包),其实也行啊,输出符合class规范的二进制字节码就行啦~~~(认真学习JVM规范吧)

 

至此,该分享的就分享完啦,有什么问题欢迎留言一块儿探讨~

相关文章
相关标签/搜索