springBoot缓存源码分析

一、springBoot与缓存

1. JSR107

Java Caching定义了5个核心接口,分别是CachingProvider, CacheManager,Cache, EntryExpiry

  • CachingProvider定义了创建、配置、获取、管理和控制多个CacheManager,一个应用可以在运行期访问多个CachingProvider
  • CacheManager定义了创建、配置、获取、管理和控制多个唯一命名的Cache,这些Cache存在于CacheManager的上下文中,一个CacheManager仅被一个CachingProvider所拥有
  • Cache是一个类似Map的数据结构并临时存储以Key为索引的值,一个Cache仅被一个CacheManager所拥有,在后面的源码分析中我们可以发现Cache其实就是一个HashMap为主的一个类
  • Entry是一个存储在Cache中的key-value这里的Entry和Map中的内部类是一个意思,所以在这里也更能确定Cache就是一个以Map为主要数据结构的类在这里插入图片描述
  • Expiry 每一个存储在Cache中的条目有一个定义的有效期。一旦超过这个时间,条目为过期的状态。一旦过期,条目将不可访问、更新和删除。缓存有效期可以通过ExpiryPolicy设置。

可以用这样一幅图总结一下:
在这里插入图片描述

2.spring的缓存抽象

在这里插入图片描述
spring提供了一系列的注解来方便我们的开发,今天我们主要是进行源代码的分析,我们以@Cacheable注解为例;

二、开始前的准备

缓存其实就是在应用程序和数据库之间加的一个中间层,用来加速数据的检索;在这里插入图片描述
所以我们今天的示例要先在数据库中创建一个User表:

1.创建User表

在这里插入图片描述

2.创建一个springBoot应用

idea上创建springBoot是很方便的这里就不演示了;
在这里插入图片描述
这些是我导入的依赖,Edit Starters是一个idea插件可以让你的springBoot项目在创建以后以勾选的方式添加依赖;

3.配置springBoot项目

主要就是一个开启缓存的注解
在这里插入图片描述
在这里插入图片描述
这里最后的debug=true开启以后就可以看到sprngBoot程序启动的时候自动配置的信息;
接下来就是代码:
首先要有一个User实体类:

@Data
public class User {
    private int id;
    private String name;
}

这里我使用了一个idealombok插件,可以让你不用再去写那些get set方法了;

Mapper:这里我们为了方便采用注解开发(但是我本人还是喜欢xml方式去写sql)

@Mapper
public interface UserMapper {

    @Select("select *from user where id = #{id}")
    User getUserById(int id);

    @Update("update user set name = #{name} where id = #{id}")
    void updateUser(User user);

    @Delete("delete from user where id = #{id}")
    void deleteUser(int id);

    @Insert("insert into user values(#{id}, #{name})")
    void insertUser(User user);
}

这里我们就有了一个基本的增删改查的接口;

Service层:这里应该是一个接口对应一个实现,为了方便我们就不写接口了

@Service
public class UserService {

    @Autowired
    UserMapper userMapper;

    @Cacheable(cacheNames = "user", key = "#root.methodName+'['+#id+']'")
    public User getUser(int id) {
        System.out.println("查询");
        User user = userMapper.getUserById(id);
        return user;
    }
}

应为我们是一个web项目,所以我们还需要一个Controller:

@RestController
public class UserController {

    @Autowired
    UserService userService;

    @GetMapping("/getUser/{id}")
    public User getUser(@PathVariable("id") int id) {
        return userService.getUser(id);
    }
}

4.演示

我们启动项目:
在这里插入图片描述
第一次访问后台并没有缓存所以我们访问了数据库有sql语句
在这里插入图片描述
当我们第二次访问这个url我们会发现我们并没有去访问数据库,甚至没有去调用UserService中的getUser方法
在这里插入图片描述

三、原理分析

在springBoot中所有的自动配置都是...AutoConfiguration所以我们去搜CacheAutoConfiguration这个类
在这个类中有一个静态内部类CacheConfigurationImportSelector他有一个selectImport方法是用来给容器中添加一些缓存要用的组件;
在这里插入图片描述
我们在这里打上断点,debug调试一下看看imports中有哪些缓存组件
在这里插入图片描述
我们可以看到这里总共有十个缓存组件;我们随便去看一个
会发现在他的注解上表明了什么时候使用这个组件;
在这里插入图片描述
那么接下来我们来看看springBoot默认使用的缓存组件是什么;
(这里就不把所有的查询结果放出了)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我们最终会发现只有SimpleCacheConfiguration是被使用的,所以也就说明默认情况下使用SimpleCacheConfiguration;
然后我们进入到SimpleCacheConfiguration中:
在这里插入图片描述
我们会发现他给springBoot容器添加了一个bean,是一个CacheManager;
ConcurrentMapCacheManager实现了CacheManager接口
在这里插入图片描述
这里要说一个@Nullable注解这个注解是说传入的参数可以为null

在写程序的时候你可以定义是否可为空指针。通过使用像@NotNull和@Nullable之类的annotation来声明一个方法是否是空指针安全的。现代的编译器、IDE或者工具可以读此annotation并帮你添加忘记的空指针检查,或者向你提示出不必要的乱七八糟的空指针检查。IntelliJ和findbugs已经支持了这些annotation。这些annotation同样是JSR 305的一部分,但即便IDE或工具中没有,这个annotation本身可以作为文档。看到@NotNull和@Nullable,程序员自己可以决定是否做空指针检查。顺便说一句,这个技巧对Java程序员来说相对比较新,要采用需要一段时间。

在这里插入图片描述
getCache方法使用了双重锁校验(这种验证机制一般是用在单例模式中)
我们可以看到如果没有Cache会调用
cache = this.createConcurrentMapCache(name);
在这里插入图片描述
这个方法会创建一个ConcurrentMapCache这个就是我们说的Cache;
在这里插入图片描述
在这个类里面有这样三个属性;

 private final ConcurrentMap<Object, Object> store;

这个就是前文中的Entry用来存放键值对;
ConcurrentMapCache中我们会看到一些操作Cache的方法我选几个重要的
在这里插入图片描述
在这里插入图片描述
lookup方法是根据key来找value的;
put方法顾名思义是用来添加键值对的;
到这里基本上就结束了,接下来我们来详细分析一下@Cacheable注解

四、@Cacheable分析

我们在上述的两个方法上打上断点;debug运行springBoot;
访问getUser接口;
在这里插入图片描述
我们会发现他来到了lookup方法这里,说明注解的执行在被注解的方法前,然后这里我们会返回null;
我们放行到下一个注解会发现;调用了put方法
在这里插入图片描述
添加了Cache;然后我们第二次对getUser接口发起请求我们会发现打断点的两个方法没有被执行在这里插入图片描述
因为在这里cache不为null了,直接被返回了;


以上就是我对于springBoot缓存的理解

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值