首页 > 其他分享 >Spring缓存框架使用及原理

Spring缓存框架使用及原理

时间:2023-09-29 23:55:16浏览次数:49  
标签:缓存 框架 Spring cache springframework import org 注解

使用

maven依赖

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

开启缓存

@SpringBootApplication
@EnableCaching
public class CacheApplication {

    public static void main(String[] args) {
        SpringApplication.run(CacheApplication.class, args);
    }

}

使用@EnableCaching注解

添加配置

server:
  port: 8080
spring:
  redis:
    host: ip
    port: 6379
    password: xxx
  cache:
    type: REDIS

表示使用Redis来实现缓存

代码中使用

import com.imooc.cache.model.User;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;


@Service
public class UserService {

    @Cacheable(value = "users")
    public List<User> getAllUsers() throws InterruptedException {
        TimeUnit.SECONDS.sleep(5);
        List<User> users = new ArrayList<>();
        users.add(new User().setUsername("lisi1").setPassword("123").setAge(21));
        users.add(new User().setUsername("lisi2").setPassword("456").setAge(22));
        return users;
    }

    @Cacheable(value = "user", key = "#p0")
    public User getUser(String userName) throws InterruptedException {
        TimeUnit.SECONDS.sleep(2);
        return new User().setUsername(userName).setPassword("123").setAge(21);
    }
}

主要是@Cacheable注解,users()方法在redis中的key为users::SimpleKey [],user()方法的key为user::${userName}

常用注解

  • @Cacheable: 方法的返回值会被缓存下来,下一次调用该方法前,会去检查缓存中是否已经有值,如果有就直接返回。如果没有,就执行方法,然后将结果缓存起来。这个注解一般用在查询方法上。
  • @CacheEvict: 清空指定缓存。一般用在更新或者删除的方法上。
  • @CachePut: 会将方法的返回值put到缓存里面缓存起来,供其它地方使用。通常用在新增方法上。
  • @Caching: 一个方法会操作多个缓存(这个在删除缓存操作中比较常见,在添加操作中不太常见)。
  • @CacheConfig: 它是一个类级别的注解,可以在类级别上配置cacheNames、keyGenerator、cacheManager、cacheResolver等。

原理分析

因为我们添加了cache的maven依赖,SpringBoot自动装配了CacheAutoConfiguration,会根据我们配置的spring.cache.type来选择不同的缓存实现,这里使用了RedisCacheConfiguration,配置了RedisCacheManager这个CacheManager,当然如果我们自己定义了,就会使用我们自己的。

因为我们使用@EnableCaching注解开启了缓存,就自动导入了CachingConfigurationSelector配置类,它又会导入ProxyCachingConfiguration,会配置BeanFactoryCacheOperationSourceAdvisor,使用的拦截器为CacheInterceptor,它就是查询、添加、删除缓存的核心。

总结起来,就是通过AOP对添加了常用的那些注解的类创建动态代理类,在方法执行前后做一些操作。

  1. 进入CacheInterceptor的invoke()方法
  2. 进入父类CacheAspectSupport的execute(CacheOperationInvoker,Method,CacheOperationContexts)方法,在此方法中处理@CacheEvict,@Cacheable等注解
  3. 先处理@CacheEvict注解,如果配置的beforeInvocation为true,就先删除缓存值
  4. 再处理@Cacheable注解,查询出缓存值,如果没查询到,就执行方法,并将结果添加到缓存中
  5. 再处理@CachePut注解,将方法返回值添加到缓存中
  6. 再处理@CacheEvict注解,如果配置的beforeInvocation为false,就后删除缓存值

关于@Cacheable注解的sync属性

设置为true的情况下,会走CacheAspectSupport的execute(CacheOperationInvoker,Method,CacheOperationContexts)方法的上面一部分,最终调用的是Cache的get(Object, Callcable)方法,Spring Cache是期望Cache的实现类在这个方法内部实现"同步"的功能,RedisCache就是通过给方法加上 synchronized 来实现同步的。

自定义CacheManager

点击查看代码
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class CacheBeanConfig extends CachingConfigurerSupport {

    @Value("${jwt.expiration:50}")
    private int jwtExpiration;

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        return RedisCacheManager.builder(factory)
                .cacheDefaults(getDefaultCacheConfiguration(jwtExpiration))
                .withInitialCacheConfigurations(getCacheConfigurations())
                .build();
    }

    /**
     * 提前创建Cache对象,可以加快一点速度
     */
    private Map<String, RedisCacheConfiguration> getCacheConfigurations() {
        Map<String, RedisCacheConfiguration> configurationMap = new HashMap<>();
        configurationMap.put("user", this.getDefaultCacheConfiguration(jwtExpiration));
        return configurationMap;
    }

    private RedisCacheConfiguration getDefaultCacheConfiguration(long seconds) {
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer();
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer))
                //默认为 name -> name + "::"
                .computePrefixWith(name -> name + ":");
        if (seconds > 0) {
            //缓存有效期配置
            redisCacheConfiguration = redisCacheConfiguration.entryTtl(Duration.ofSeconds(seconds));
        }
        return redisCacheConfiguration;
    }
}

相比默认的CacheManager,修改了key和value的序列化器,增加了过期时间

参考

Spring Cache,从入门到真香

标签:缓存,框架,Spring,cache,springframework,import,org,注解
From: https://www.cnblogs.com/strongmore/p/17131272.html

相关文章

  • Java集合框架(部分)
    类图List:有序可重复集合特点1.元素允许重复2.元素有序(元素的顺序就是插入时的顺序)3.元素可以通过索引来访问或者设置{ArrayLIst:底层为数组,查询速度快,增删慢LinkedList:底层是链表,查询速度慢,增删快两者的优缺点,:效率高,线程不安全}Set:无序不可重复集合HashSet:底层为数组,......
  • java springboot项目,mybatisplus,import com.baomidou.mybatisplus.core.mapper.BaseMa
    <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.1.2</version><!--用版本2.1.9就不行,UserMapper里BaseMapper爆红--></dependency>我的结果是,......
  • Go每日一库之184:katana(新一代爬虫框架)
    项目链接https://github.com/projectdiscovery/katana项目简介katana是一个使用golang编写的新一代爬虫框架,支持HTTP和headless抓取网页信息不仅可以作为库集成到Golang项目,还可以通过命令行直接抓取,对于有一些轻量级的抓取任务的开发者配合jq一起使用简直就是福......
  • Go每日一库之180:fastcache(协程安全且支持大量数据存储的高性能缓存库)
    fastcache是一个线程安全并且支持大量数据存储的高性能缓存组件库。这是官方Github主页上的项目介绍,和fasthttp名字一样以fast打头,作者对项目代码的自信程度可见一斑。此外该库的核心代码非常轻量,笔者本着学习的目的分析下内部的代码实现。基准测试官方给出了fastca......
  • Go每日一库之146:bbs-go(bbs框架)
    概要bbs-go是一款基于Go语言研发的开源、前后端分离、精美小巧、跨平台的社区系统。初期该项目仅用过学习和交流,开源之后越来越多的小伙伴儿开始喜欢和关注他,这也是我长期升级和维护的动力。bbs-go为前后端分离设计,后端接口服务使用简洁的Go语言进行开发,前端页面使用Vue.js进......
  • Go每日一库之135:Ent(Facebook 开源 Golang 实体框架)
    对于后端开发者来说,一款好用的框架能够大大提升应用的开发效率。为了降低开发者使用TiDB的门槛,方便开发者快速连接到TiDB,我们也在和合作伙伴一起,逐步完善面向主流开发语言和框架的连接支持。近日,Facebook开源的Golang实体框架Ent完成了对TiDB数据库的支持。Ent是......
  • SpringCloud
    目录Springcloud介绍注册中心(Eureka)背景注册中心案例总结负载均衡(Ribbon)测试使用负载均衡RibbonRibbon负载均衡流程Ribbon的IRule常见负载均衡策略Ribbon的使用方法远程调用(OpenFeign)Feign使用连接池注册中心(Nacos)测试配置集群命名空间Nacos非临时实例配置中心(Nacos)客......
  • gitlab--在 k8s 里通过 helm 部署 runner、使用缓存 cache、使用制品 artifacts
    安装helm链接:https://www.cnblogs.com/zouzou-busy/p/16134885.html配置chart存储库#添加chart存储库[root@master1~]#helmrepoaddgitlabhttps://charts.gitlab.io"gitlab"hasbeenaddedtoyourrepositories#查看存储库[root@master1~]#helmrepolist......
  • vue前端框架ruoyi介绍
    Ruoyi是一个基于Vue.js和SpringBoot框架构建的开源前后端分离的企业级快速开发平台。它遵循了前后端分离的架构模式,将前端和后端进行解耦,使得系统更加灵活、可扩展和易于维护。Ruoyi的前端部分采用了Vue.js框架,这是一个流行的JavaScript前端框架,专注于构建用户界面。Vue......
  • Spring boot 处理大文件上传完整代码
    这篇文章主要介绍了Spring boot 处理大文件上传,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下 在Web上处理大文件上传时,可以使用以下方法来优化和处理大文件的上传:1.前端处理:在前端使用合适的文件上传库或组件,例......