欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

springboot 缓存@EnableCaching实例

程序员文章站 2022-04-15 09:21:06
目录springboot 缓存@enablecachingspring @enablecaching的工作原理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既处理调用前缓存操作,也处理调用返回时缓存操作

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。