zoukankan      html  css  js  c++  java
  • SpringBoot系列(十五)整合缓存,项目会用得到的技术

    一、缓存有什么用?

     缓存应该是我们每一个系统都应该考虑使用的,这样可以加速系统的访问,提升系统的性能。比如我们经常需要访问的高频数据,将此类数据放在缓存中,可以大幅度提升系统的响应速度。原因就是一般来说我们的数据都是存在数据库中,但是高频的访问数据库不仅会对数据库造成压力,一定程度上还会影响响应速度,影响用户体验。如果引入了缓存,不仅能提升访问性能的同时降低数据库的压力。

    二、JSR107规范

     JSR是Java Specification Requests的缩写,意思是Java 规范提案。是指向JCP(Java Community Process)提出新增一个标准化技术规范的正式请求。任何人都可以提交JSR,以向Java平台增添新的API和服务。JSR已成为Java界的一个重要标准。

    规范:

     JCache规范定义了一种对Java对象临时在内存中进行缓存的方法,包括对象的创建、共享访问、假脱机(spooling)、失效、各JVM的一致性等,可被用于缓存JSP内最经常读取的数据,如产品目录和价格列表。利用JCACHE,多数查询的反应时间会因为有缓存的数据而加快(内部测试表明反应时间大约快15倍)。

     Java Caching定义了5个核心接口,分别是CachingProvider, CacheManager, Cache, Entry 和 Expiry。其中CacheProvider就是缓存提供器,其中包含了多个缓存管理器(CacheManager),缓存管理器之下才是我们需要用到的缓存(Cache),缓存的形式就是键值对,即entry对象(Entry),每一个entry对象会对应一个Expiry,即可以对每一条缓存数据设置有效期。

    ​ 上面都是抄过来的废话,看下面,实际操作一下。

    三、Spring缓存抽象

    Spring 3.1开始定义了org.springframework.cache.Cache 和org.springframework.cache.CacheManager接口来统一不同的缓存技术;并支持使用JCache(JSR-107)注解简化我们开发。SpringBoot对缓存整合提供了很好的支持,支持不同的缓存规范(所谓的规范就是相当于面向接口编程,不同的缓存有不同的实现)。

    其中Cache接口为缓存的组件规范定义,包含缓存的各种操作集合;
    Cache接口下Spring提供了各种xxxCache的实现;如RedisCache,EhCacheCache , ConcurrentMapCache等;下面我们来看看,SpringBoot中默认的一些缓存配置与实现。默认的是SimpleCache。

    四、SpringBoot中的缓存-注解开发

    新建SpringBoot web项目,加入依赖配置:SpringBoot版本为2.2.6.RELEASE 库存文章了,版本是去年的。

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

    然后我们逐个介绍一下缓存开发中用到的一些注解。

    • @EnableCaching
    • @Cacheable
    • @CachePut
    • @CacheEvict
    • @Caching
    • @CacheConfig

    1.@EnableCaching

     这个注解应该是最先了解的,把它放在启动类上面,表示开启基于注解的缓存,然后你用那些缓存相关的注解就能被Spring容器扫描到。这个注解不能缺,不然项目会报错。

    @EnableCaching
    @SpringBootApplication
    public class DemoCacheApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(DemoCacheApplication.class, args);
        }
    }
    

    2.@Cacheable

     这个注解有很多的属性,可以定义一些缓存的规则。主要是用于方法之上,将方法的结果作为缓存的值,默认情况下将方法的参数作为缓存的键(key),也就是key-value的形式存储数据。首先介绍一下这个注解的运行机制:首先在方法运行之前,先根据注解配置的value或者是cacheNames到cacheManage中去查询缓存组件即Cache,当然如果第一次没有这个缓存就会自动创建。获取到缓存组件之后就用我们设置的key属性,或者是keyGenerator策略生成的key去查询键对应的缓存值,对应上面的entry对象。如果查到了值就返回给请求客户端,如果没有查到这个值就调用方法,然后将方法返回的结果缓存起来。

    这里我们来说一说这个注解里面的一些属性的用法:

    • value/cacheNames:这两个属性是一样的,都是指定一个缓存组件的名字,当然这个可以指定多个,是一个数组。
    • key/keyGenerator:这两个有一定的区别,但是用的时候只需要用其中一个就行了。key是我们可以直接指定这个缓存结果对应的key是什么,到时候直接去Cache里面查就行了,keyGenerator就是可以自定义一个key的生成策略,然后生成key,两者从结果上来看都是生成了key,所以两者只需要用其中一个就OK了。
    • condition:在符合这个条件下才进行缓存
    • unless:当这个条件为假的时候才进行缓存,与condition相反

    当然还有cacheManager(缓存管理器)以及cacheResolver(缓存解析器),这两个都可以自己定义。两个都差不多,二者用其中一个就OK。

    下面我们来看看SpEl写法,因为我们的key或者是condition,或者是unless属性都会用到这个写法。

    来自官方的spel 语法

    Name Location Description Example
    methodName Root object 被调用方法的名称 #root.methodName
    method Root object 被调用的方法 #root.method.name
    target Root object 被调用的目标对象 #root.target
    targetClass Root object 被调用目标的类 #root.targetClass
    args Root object 用于调用目标的参数(作为数组) #root.args[0]
    caches Root object 运行当前方法的缓存集合 #root.caches[0].name
    Argument name Evaluation context 任何方法参数的名称。如果名称不可用(可能是由于没有调试信息),则参数名称也可在代表参数索引的#a<#arg> where下#arg(从 开始0)。 #iban or #a0 (you can also use #p0 or #p<#arg> notation as an alias).
    result Evaluation context 方法调用的结果(要缓存的值)。仅在unless 表达式、cache put表达式(用于计算key)或cache evict 表达式(何时beforeInvocationfalse)中可用。对于支持的包装器(例如 Optional),#result指的是实际对象,而不是包装器。 #result

    具体使用如下:

    @GetMapping("/cacheAble")
    @Cacheable(value = "cache",key = "#root.args[0]",condition = "#id>20")
    public  Student cacheAble(@RequestParam Integer id) {
        Student student = (Student) hashMap.get(id);
        System.out.println("第一次调用了方法,添加缓存");
        return student;
    }
    

    上面就相当于是将第一个方法参数id作为缓存的key ,返回值Student 作为值。缓存的名称就是cache,设置在参数id大于20的时候才进行缓存,unless 则是相反的。

    3.@CachePut

    这个注解是用来更新缓存的,一般情况下都是用在更新数据的接口上,示例如下:

    @PostMapping("/putCache")
    @CachePut(value = "cache",key = "#result.id")
    public Student putCache(@RequestBody Student student) {
        hashMap.replace(student.getId(),student);
        System.out.println("调用了方法,也更新了缓存");
        return student;
    }
    

    4.@CacheEvict

    删除缓存的注解,可以设置删除全部缓存还是删除部分缓存数据。如下

    @CacheEvict(value = "cache",key = "#id",beforeInvocation = true,allEntries = false)
    @GetMapping("/cacheEvict")
    public void cacheEvict(@RequestParam Integer id) {
        hashMap.remove(id);
        System.out.println("缓存删除");
    }
    

    beforeInvocation 设置为true ,表示在方法执行之前进行缓存删除,默认为false,``allEntries`设置为true ,表示删除这个缓存名称下面的所有缓存。

    5.@Caching

    借助官方的话说,有时,需要指定多个相同类型的注解(例如@CacheEvict@CachePut)——例如,因为不同缓存之间的条件或键表达式不同。@Caching允许在同一方法上使用多个嵌套的 @Cacheable@CachePut@CacheEvict注释。实际上就是,各个缓存注解可以配合使用,操作不同的缓存空间。

     @Caching(
         cacheable = {
             @Cacheable(value = "cache",key = "#id"),
             @Cacheable(value = "cache1",key = "#id")
         },
         evict = {@CacheEvict(value = "cache2",key = "#id")}
     )
    @GetMapping("/caching")
    public Student caching(@RequestParam Integer id) {
        Student student = (Student)hashMap.get(id);
        System.out.println("新增缓存了,也删除了缓存,但是操作的cache不一样");
        return student;
    }
    

    代码实现的就是将数据缓存到cache,cache1,再将cache2的缓存删除掉。

    6.@CacheConfig

    这是一个类级别的缓存配置注解,像缓存名称,缓存处理器(cacheResolver),缓存管理器(cacheManager),这些配置可以直接配置到类上面,这样方法对应的就能少些一些重复代码。

    //注解的四个属性
    String[] cacheNames() default {};
    
    String keyGenerator() default "";
    
    String cacheManager() default "";
     
    String cacheResolver() default "";
    

    示例: 在类上面,加上注解,配置好对应的缓存名称,key生成策略等,keyGenerator,cacheManager,cacheResolver这三个东西留着下篇文章将redis缓存的时候讲,主要是比较多。

    @CacheConfig(cacheNames = "chache")
    public class CacheController {}
    

    确实,我们的缓存还能从cacheManager中获取,这很好理解,cacheManager是管理缓存的,当然也能获取缓存了。

    @GetMapping("/get")
    public Student getCache(@RequestParam Integer id){
        Cache cache = cacheManager.getCache("cache");
        Cache.ValueWrapper student = cache.get(id);
        Object o = student.get();
        return (Student) o;
    }
    

    由于SpringBoot的良好扩展性,CacheManager,CacheResolver,
    KeyGenerator都可以自己配置,具体的下一篇文章会介绍。

    心诚不灭
  • 相关阅读:
    Oracle EBS-SQL (PO-3):检查期间手工下达的采购订单记录数.sql
    Oracle EBS-SQL (PO-2):检查当月到货补单的记录数.sql
    Oracle EBS-SQL (PO-1):检查供货比例异常.sql
    Oracle EBS-SQL (MRP-2):检查期间主计划录入记录数.sql
    Oracle EBS-SQL (MRP-1):检查期间内计划完成的任务.sql
    Oracle EBS-SQL (INV-3):检查仓库库存价值明细.sql
    Oracle EBS-SQL (INV-2):检查帐户别名发放记录.sql
    Oracle EBS-SQL (INV-1):检查物料成本为0并且物料状态不是'NEW'的物料.sql
    Oracle EBS-SQL (BOM-13):检查未定义库存分的物料类.sql
    Oracle EBS-SQL (BOM-12):BOM清单查询
  • 原文地址:https://www.cnblogs.com/swzx-1213/p/14974863.html
Copyright © 2011-2022 走看看