springboot 缓存@EnableCaching实例
springboot 缓存@enablecaching
很多时候系统的瓶颈都在一些比较复杂的io操作,例如读取数据库,如果一些比较稳定的数据,一般的解决方案就是用缓存。spring boot提供了比较简单的缓存方案。只要使用 @enablecaching即可完成简单的缓存功能。
缓存的实现有多种实现,concurenthashmapcache , guavacache, encachecache等多种实现,spring boot 有默认的实现。本文不深入源码解读,首先用起来。
此处我们模拟要缓存的user
class user { private long id; private string name; // setter getter }
然后我们业务对象:
import javax.annotation.postconstruct; import org.springframework.cache.annotation.cacheevict; import org.springframework.cache.annotation.cacheput; import org.springframework.cache.annotation.cacheable; import org.springframework.cache.annotation.enablecaching; import org.springframework.stereotype.component; /** * @author micro * @date 2017年8月2日 * @description : */ @component @enablecaching public class userdao { private map<long, user> usermap; @postconstruct public void init() { //模拟数据库 usermap = new hashmap<long, user>(); usermap.put(1l, new user(1l,"micro1")); usermap.put(2l, new user(2l, "micro2")); } @cacheable("user") // 注解key属性可以执行缓存对象user(可以理解为一个map)的key public user getuser(long userid) { system.out.println("查询数据库:userid ->" + userid); return usermap.get(userid); } @cacheable(value = "namecache", key = "#name") public user getuserbyname(long userid, string name) { system.out.println("查询数据库:userid ->" + userid); return usermap.get(userid); } @cacheable("namecache") public user getuserbyname(string name) { system.out.println("查询数据库:username : " + name); for (long k : usermap.keyset()) { if (usermap.get(k).equals(name)) { return usermap.get(k); } } return null; } @cacheput("user") // 与cacheable区别就是cacheable先看缓存如果有,直接缓存换回,cacheput则是每次都会调用并且把返回值放到缓存 public user getuser2(long userid) { system.out.println("查询数据库:userid : " + userid); return usermap.get(userid); } @cacheevict("user") public void removefromcache(long userid) { return ; } }
然后我们编写启动类:
@springbootapplication public class cachetest implements commandlinerunner { @autowired private userdao userdao; public static void main(string[] args) { new springapplication(cachetest.class).run(args); } @override public void run(string... args) throws exception { system.out.println("第一次查询"); system.out.println(userdao.getuser(1l)); system.out.println("第二次查询"); system.out.println(userdao.getuser(1l)); userdao.removefromcache(1l);// 移除缓存 system.out.println("第三次查询"); userdao.getuser(1l);// 没有缓存了 system.out.println("--------"); // 测试不同的key缓存 userdao.getuserbyname("micro1"); userdao.getuserbyname(1l, "micro1");// 指定了参数name 为key 此次读取缓存 } }
打印结果:
第一次查询
查询数据库:userid ->1
user@65da01f4
第二次查询
user@65da01f4
第三次查询
查询数据库:userid ->1
--------
查询数据库:username : micro1
spring @enablecaching的工作原理
1、开发人员使用注解@enablecaching
2、注解@enablecaching导入cachingconfigurationselector
3、cachingconfigurationselector根据注解@enablecaching 属性advicemode mode决定引入哪些配置类
-
proxy
: autoproxyregistrar,proxycachingconfiguration; -
aspectj
: aspectjcachingconfiguration;
本文以mode=proxy为例;
4、cachingconfigurationselector导入autoproxyregistrar会确保容器中存在一个自动代理创建器(apc);
- 用于确保目标bean需要被代理时有可用的代理创建器
5、proxycachingconfiguration向容器定义如下基础设施bean
- 名称为org.springframework.cache.config.internalcacheadvisor类型为beanfactorycacheoperationsourceadvisor的bean
- 名称为cacheoperationsource类型为cacheoperationsource的bean
用于获取方法调用时最终应用的spring cache注解的元数据
- 名称为cacheinterceptor类型为cacheinterceptor的bean
一个methodinterceptor,包裹在目标bean外面用于操作cache的aop advice。
6、autoproxyregistrar在容器启动阶段对每个bean创建进行处理,如果该bean中有方法应用了spring cache注解,为其创建相应的代理对象,包裹上面定义的beanfactorycacheoperationsourceadvisor bean;
7、使用了spring cache注解的bean方法被调用,其实调用首先发生在代理对象上,先到达cacheinterceptor,然后才是目标bean方法的调用;
- cacheinterceptor既处理调用前缓存操作,也处理调用返回时缓存操作
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。
上一篇: 历史上允礼是怎么死的?真的被雍正所杀?
下一篇: java gui详解贪吃蛇小游戏实现流程