简易入门

一、作用

当我们在调用一个缓存方法时会根据相关信息和返回结果作为一个键值对存放在缓存中,等到下次利用同样的参数来调用该方法时将不再执行该方法,而是直接从缓存中获取结果进行返回。

二、启用方式

1.POM.xml 文件中添加spring cache依赖(Spring Boot)

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

2.添加一种cacheManager的bean

若注解了@EnableCaching,则spring可自动发现并配置cacheManager,只要有一种可用于缓存提供的即可,详情见文献[1]。常用的有Ehcache、redis等实现

为方便起见,这里使用最简单的内存map实现。(可以使用Redis来提供CacheManager。详见附录)

    @Bean
public CacheManager cacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(Collections.singletonList(new ConcurrentMapCache("models")));
return cacheManager;
}

3.启用注解@EnableCaching

    @Configuration
@EnableCaching
public class CacheConfiguration {
//...
}

三、使用方式

三个主要的注解 Cacheable (最常用的注解,用于标注需要缓存方法)、CacheEvict(用于仅清除缓存)、CachePut(用于仅存放缓存)

先定义一个测试POJO: TestModel。 含有name和address两个字符串变量。

    class TestModel {
String name;
String address;
// 省略getter和setter
}

1.Cacheable

例子:

    @Cacheable(value = "models", key = "#testModel.name", condition = "#testModel.address !=  '' ")
public TestModel getFromMem(TestModel testModel) throws InterruptedException {
TimeUnit.SECONDS.sleep(1);
testModel.setName(testModel.getName().toUpperCase());
return testModel;
}

例子里的注解@Cacheable中存在有以下几个元素

  • value (也可使用 cacheNames) : 可看做命名空间,表示存到哪个缓存里了。
  • key : 表示命名空间下缓存唯一key,使用Spring Expression Language(简称SpEL,详见参考文献[5])生成。
  • condition : 表示在哪种情况下才缓存结果(对应的还有unless,哪种情况不缓存),同样使用SpEL

当第一次使用

    {name: 'XiaoMing', address: 'ChengDu'}

调用getFromMem时,会等待一秒钟,然后返回

    {name: 'XIAOMING', address: 'ChengDu'}

当再次使用name为’XiaoMing’的对象作为参数调用getFromMem时,会立即返回上一个结果,无论参数中的address是什么。

但是如果第一次调用时,address为空字符串,第二次调用仍然需要等待一秒钟,这就是condition的作用。

2.CacheEvict

例子:

    @CacheEvict(value = "models", allEntries = true)
@Scheduled(fixedDelay = 10000)
public void deleteFromRedis() {
} @CacheEvict(value = "models", key = "#name")
public void deleteFromRedis(String name) {
}

例子里的注解 @CacheEvict 中存在有以下几个元素
- value (也可使用 cacheNames) : 同Cacheable注解,可看做命名空间。表示删除哪个命名空间中的缓存

- allEntries: 标记是否删除命名空间下所有缓存,默认为false

- key: 同Cacheable注解,代表需要删除的命名空间下唯一的缓存key。

例子中第一段,与

@Scheduled

注解同时使用,每十秒删除命名空间name下所有的缓存。

第二段,调用此方法后删除命名空间models下, key == 参数 的缓存

同样含有unless与condition

3.CachePut

例子

    @CachePut(value = "models", key = "#name")
public TestModel saveModel(String name, String address) {
return new TestModel(name, address);
}

例子里的注解 @CachePut 中存在有以下几个元素

  • value: 同上
  • key: 同上
  • condition(unless): 同上

比如可用于后台保存配置时及时刷新缓存。

以上三个注解中还有少量未提到的元素,于附录中叙述。

文献与深入

1.文献

[1] Spring Boot中的缓存支持(一)注解配置与EhCache使用
[2]
Spring Boot中的缓存支持(二)使用Redis做集中式缓存

[3]
A Guide To Caching in Spring

[4]
spring cache官方文档

[5]
Spring Expression Language官方文档

2.创建RedisCacheManager

这里我们依赖spring redis

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

然后在配置中添加RedisConnectionFactory用于获取redis链接

    @Bean
public RedisConnectionFactory redisConnectionFactory() {
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
jedisConnectionFactory.setHostName("127.0.0.1");
jedisConnectionFactory.setPort(6379);
return jedisConnectionFactory;
}

还需要一个RedisTemplate。RedisTemplate提供了对Jedis API的高级封装,使用serializers序列化key和value,用于将java与字符串相互转换。这里使用Jackson的serializers(详见附录),来将java对象序列化为json字符串。

jackson类似gson

    @Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
Jackson2JsonRedisSerializer<Object> serializer = jackson2JsonRedisSerializer();
redisTemplate.setConnectionFactory(redisConnectionFactory());
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(serializer);
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(serializer);
return redisTemplate;
}

然后就可以得到一个RedisCacheManager

    @Bean
public CacheManager redisCacheManager() {
RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate());
cacheManager.setDefaultExpiration(300);
cacheManager.setLoadRemoteCachesOnStartup(true); // 启动时加载远程缓存
cacheManager.setUsePrefix(true); //是否使用前缀生成器
// 这里可进行一些配置 包括默认过期时间 每个cacheName的过期时间等 前缀生成等等
return cacheManager;
}

运行文中”三”示例程序,并且可以观察到redis中多了一个models:XiaoMing的key
其中的值为

[\"com.xxx.TestModel\",{\"name\":\"XIAOMING\",\"address\":\"ChengDu\"}]


注意这里的序列化的实现方式,保存了对象类的信息,保证方法返回与缓存返回一致(当然如果你的setter getter实现不一致,还是会造成不一致的)。

我曾经因为手动序列化造成了一个BUG,一个有序Map存进去,反序列化出来失去了有序性  ,当然方法返回值定义成了Map而不是SortedMap也是一个重要原因

3. 上一条中使用的Jackson2JsonRedisSerializer

    @Bean
public Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer() {
final Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
final ObjectMapper objectMapper = Jackson2ObjectMapperBuilder
.json().build();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
return jackson2JsonRedisSerializer;
}

4. Cache* 注解中未提到的元素

共同的:

  1. keyGenerator: 实现 org.springframework.cache.interceptor.KeyGenerator 接口的类bean,用于统一自定义生成key
  2. cacheManager: 用于选择使用哪个cacheManager
  3. cacheResolver: 实现 org.springframework.cache.interceptor.CacheResolver 接口的类bean,用于自定义如何处理缓存

CacheEvict:

  1. beforeInvocation: bool值,标志是否在调用前就清除缓存。防止方法因为异常意外退出。

Cacheable:

  1. sync: 是否同步  从相同key加载值 的方法,原文为:

    Synchronize the invocation of the underlying method if several threads are
    attempting to load a value for the same key

    如何同步加载缓存,具体需要看CacheManager的实现。(2019年10月11日 此部分在https://www.cnblogs.com/imyijie/p/11651679.html SpringCache - 请求级别缓存的简易实现 有进一步的讨论)

5. 关于缓存TTL等设置

请查看各 CacheManager实现 的配置。

SpringCache缓存初探的更多相关文章

  1. WEB缓存初探

    WEB缓存初探 概念理解 缓存--缓存就是数据交换的缓冲区(称作Cache) 缓存 的作用说白了就是用来就近获取东西,比如我们会把已经拿到的常用的东西放在手边(与自己相对较近的地方),方便下次需要时去 ...

  2. ibatis缓存初探(1)

    一,IBATIS 缓存机制使用 1,sqlMapConfig.xml中配置   1.SqlMapConfig.xml中 <settings cacheModelsEnabled="tr ...

  3. HTTP缓存初探

    缓存的作用 用户访问一个web页面的频率远高于web页面更新的频率,因此多数时候用户从服务器获取的html.js.css以及图片等内容都是相同的,如果每次访问都从服务器获取这些静态内容即降低了页面加载 ...

  4. SpringCache - 请求级别缓存的简易实现

    前言 在SpringCache缓存初探中我们研究了如何利用spring cache已有的几种实现快速地满足我们对于缓存的需求.这一次我们有了新的更个性化的需求,想在一个请求的生命周期里实现缓存. 需求 ...

  5. @ENABLECACHING 基于注解的缓存

    @EnableCaching• @Cacheable指定一个或多个Cache名字,同属性cacheNamesSpring Cache 使用 ---@EnableCaching @Cacheable 注 ...

  6. Atitit s2018 s4 doc list dvchomepc dvccompc.docx .docx \s2018 s4 doc compc dtS44 \s2018 s4 doc dvcCompc dtS420 \s2018 s4f doc homepc \s2018 s4 doc compc dtS44\(5 封私信 _ 44 条消息)WebSocket 有没有可能取代 AJAX

    Atitit s2018 s4 doc list dvchomepc dvccompc.docx .docx \s2018 s4 doc compc dtS44 \s2018 s4 doc dvcCo ...

  7. SpringBoot基础系列-SpringCache使用

    原创文章,转载请标注出处:<SpringBoot基础系列-SpringCache使用> 一.概述 SpringCache本身是一个缓存体系的抽象实现,并没有具体的缓存能力,要使用Sprin ...

  8. MyBatis 一级缓存、二级缓存全详解(一)

    目录 MyBatis 一级缓存.二级缓存全详解(一) 什么是缓存 什么是MyBatis中的缓存 MyBatis 中的一级缓存 初探一级缓存 探究一级缓存是如何失效的 一级缓存原理探究 还有其他要补充的 ...

  9. Spring优雅整合Redis缓存

    “小明,多系统的session共享,怎么处理?”“Redis缓存啊!” “小明,我想实现一个简单的消息队列?”“Redis缓存啊!” “小明,分布式锁这玩意有什么方案?”“Redis缓存啊!” “小明 ...

随机推荐

  1. jQuery插件Flot的介绍

    Flot采用Canvas绘制图形(Web总共就有三种常见方式来绘制图形,不了解的同学请看这篇文章),在数据量非常大的时候,你需要考虑浏览器端的性能问题.顺便提一句,D3是采用SVG来绘制图形的,从我自 ...

  2. Spring EL中的类操作符

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://ww ...

  3. 负载均衡软件LVS分析三(配置)

    LVS集群有DR.TUN.NAT三种配置模式,可以对www服务.FTP服务.MAIL服务等做负载均衡,下面通过搭建www服务的负载均衡实例,讲述基于DR模式的LVS集群配置. 一. Director ...

  4. ORACLE的Dead Connection Detection浅析

    在复杂的应用环境下,我们经常会遇到一些非常复杂并且有意思的问题,例如,我们会遇到网络异常(网络掉包.无线网络断线).客户端程序异常(例如应用程序崩溃Crash).操作系统蓝屏.客户端电脑掉电.死机重启 ...

  5. 定时任务管理中心(dubbo+spring)-我们到底能走多远系列47

    我们到底能走多远系列47 扯淡: 又是一年新年时,不知道上一年你付出了多少,收获了多少呢?也许你正想着老板会发多少奖金,也许你正想着明年去哪家公司投靠. 这个时间点好好整理一下,思考总结一下,的确是个 ...

  6. IE和FF的差异

    ie和ff的差异   1. document.form.item 问题 1)现有问题: 现有代码中存在许多 document.formName.item("itemName") 这 ...

  7. redis&rabbitMQ安装

    前言: 学习python已经有一段时间了,最近在学twisted(博客:twisted安装),redis,rabbitMQ感觉有点难度,所以还是写下博客整理下. 一.Redis的安装 redis是一种 ...

  8. JavaScript———从setTimeout与setInterval到AJAX异步

    setTimeout与setInterval执行 首先我们看一下以下代码打印结果 console.log(1); setTimeout(function() { console.log(2); },1 ...

  9. asp.net core mvc权限控制:在视图中控制操作权限

    在asp.net core mvc中提供了权限验证框架,前面的文章中已经介绍了如何进行权限控制配置,权限配置好后,权限验证逻辑自动就会执行,但是在某些情况下,我们可能需要在代码里或者视图中通过手工方式 ...

  10. Weex系列二、显示图片

    上次我们创建了一个简单的Weex的demo. 一.常用的类 WXSDKEngine:SDK开放的绝大多数接口都在此有声明. WXLog: 用来打印日志. WXDebugTool: weex提供的对外调 ...