SpringBoot与缓存

SpringBoot与缓存

1.JSR107缓存规范

JSR是Java Specification Requests 的缩写 ,Java规范请求 , JSR-107就是关于如何使用缓存的规范。

Java Caching定义了5个核心接口,分别是CachingProvider, CacheManager, Cache, Entry 和 Expiry。

CachingProvider定义了创建、配置、获取、管理和控制多个CacheManager。一个应用可以在运行期访问多个 CachingProvider。

CacheManager定义了创建、配置、获取、管理和控制多个唯一命名的Cache,这些Cache存在于CacheManager 的上下文中。一个CacheManager仅被一个CachingProvider所拥有。

Cache是一个类似Map的数据结构并临时存储以Key为索引的值。一个Cache仅被一个CacheManager所拥有。

Entry是一个存储在Cache中的key-value对。

Expiry 每一个存储在Cache中的条目有一个定义的有效期。一旦超过这个时间,条目为过期的状态。一旦过期,条 目将不可访问、更新和删除。缓存有效期可以通过ExpiryPolicy设置。

SpringBoot与缓存_第1张图片

需要依赖jar包

<dependency>
    <groupId>javax.cachegroupId>
    <artifactId>cache-apiartifactId>
dependency>

需要提醒的是,该技术目前已被spring缓存抽象逐渐替代,如果想要更多了解的话,请访问官方文档

https://www.bookstack.cn/read/spring-5-framework-doc/32-32-4.md该处为spring文档中关于jsr107的部分介绍。

2.spring缓存抽象

Spring从3.1开始定义了org.springframework.cache.Cache和org.springframework.cache.CacheManager接口来统一不同的缓存技术;并支持使用JCache(JSR-107)注解简化我们开发;

Cache接口为缓存的组件规范定义,包含缓存的各种操作集合;

Cache接口下Spring提供了各种xxxCache的实现;如RedisCache,EhCacheCache , ConcurrentMapCache等;

每次调用需要缓存功能的方法时,Spring会检查检查指定参数的指定的目标方法是否已经被调用过;如果有就直接从缓存中获取方法调用后的结果,如果没有就调用方法并缓存结果后返回给用户。下次调用直接从缓存中获取。

使用Spring缓存抽象时我们需要关注以下两点;

1、确定方法需要被缓存以及他们的缓存策略

2、从缓存中读取之前缓存存储的数据

部分概念以及缓存注解

Cache 缓存接口,定义缓存操作。
CacheManager 缓存管理器,管理各种缓存(Cache)组件
keyGenerator 缓存数据时key生成策略
serialize 缓存数据时value序列化策略
@Cacheable 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存
@CacheEvict 清空缓存
@CachePut 保证方法被调用,又希望结果被缓存
@EnableCaching 开启基于注解的缓存

3.简单测试缓存

搭建SpringBoot基本运行环境并与Mybatis整合,在这里不进行赘述。

我们直接进行下列测试。
SpringBoot与缓存_第2张图片
在对页面进行三次刷新之后我们可以看到的结果。我们可以看到并没有缓存的情况。

首先我们测试@Cacheable注解,该注解可对方法执行后的结果进行缓存。

@SpringBootApplication
@EnableCaching //开启缓存的注解支持
public class CacheApplication {

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

}


//在service层进行缓存测试
 @Cacheable(value={"emp"})
    public Employee getEmployeeById(Integer id){
        System.out.println("开始查询");
        return mapper.getElementById(id);
    }

摘录cacheable的部分源码。

public @interface Cacheable {
    @AliasFor("cacheNames")
    String[] value() default {};//指定缓存名称,便于缓存管理器(cachemanager)进行管理,唯一属性类似id
    @AliasFor("value")
    String[] cacheNames() default {};

    String key() default "";//缓存数据时的key,默认使用方法参数的值,也可使用spel表达式

    String keyGenerator() default "";//key的生成器,与key二选一使用

    String cacheManager() default "";

    String cacheResolver() default "";

    String condition() default "";//制定符合条件情况下进行缓存

    String unless() default "";//与condition相反

    boolean sync() default false;//是否使用异步模式
}

连续多次刷新后仍然只有一个日志记录,说明缓存已生效。
在这里插入图片描述

4.原理的简单解析

我们都知道,SpringBoot内部集成了大量的自动配置类,我们可以通过配置查看那个自动配置类执行了,在配置文件中输入

debug=true

可以打开配置报告。

这里只进行部分摘录

GenericCacheConfiguration:
      Did not match:
         - @ConditionalOnBean (types: org.springframework.cache.Cache; SearchStrategy: all) did not find any beans of type org.springframework.cache.Cache (OnBeanCondition)
      Matched:
         - Cache org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration automatic cache type (CacheCondition)
         
HazelcastCacheConfiguration:
      Did not match:
      
JCacheCacheConfiguration:
      Did not match:

SimpleCacheConfiguration matched: //该配置类在容器中注册了cachemanager(currentCacheManager)
									可以获取和创建ConcurrentMapCache类型的缓存。该缓存将数据存入										map中
      - Cache org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration automatic cache type (CacheCondition)
      
      。。。。。。。。。。。

缓存的运行流程。

1.方法运行之前,去查询cache,按照指定名称进行获取。(获取缓存)

public Cache getCache(String name) {
        Cache cache = (Cache)this.cacheMap.get(name);

2.第一次获取缓存,如果没有查找到,会创建Cache组件

if (cache == null && this.dynamic) {
            synchronized(this.cacheMap) {
                cache = (Cache)this.cacheMap.get(name);
                if (cache == null) {
                    cache = this.createConcurrentMapCache(name);
                    this.cacheMap.put(name, cache);
                }
            }
        }

3.去cache中使用方法参数(key)查询缓存内容。

protected Object lookup(Object key) {
        return this.store.get(key);
    }

4.没有内容,调用方法。

5.将方法返回结果加入缓存。

key生成策略

public static Object generateKey(Object... params) {
        if (params.length == 0) {//无参
            return SimpleKey.EMPTY;
        } else {
            if (params.length == 1) {//一个参数
                Object param = params[0];
                if (param != null && !param.getClass().isArray()) {
                    return param;
                }
            }

            return new SimpleKey(params);//多参
        }
    }

s[0];
if (param != null && !param.getClass().isArray()) {
return param;
}
}

        return new SimpleKey(params);//多参
    }
}

你可能感兴趣的:(SpringBoot与缓存)