spring框架cacheAnnotation缓存注释声明解析

目录
  • 1.基于注释声明缓存
    • 1.1@EnableCaching
    • 1.2@Cacheable
      • 1.2.1默认key生成规则
      • 1.2.2声明自定义key 生成
      • 1.2.3默认的cache resolution
      • 1.2.4同步缓存
      • 1.2.5 缓存的条件
      • 1.2.6可用的Spel 评估上下文

1.基于注释声明缓存

声明缓存,Spring缓存抽象提供了一个java annotation集合.

@Cacheable:触发缓存填充.

@CacheEvict: 触发缓存删除.

@CachePut: 不干扰方法执行的情况下更新缓存.

@Caching: 把多种缓存操作应用重组到一个方法上

@CacheConfig: 在类上设置,将一些共用缓存相关设置共享

1.1@EnableCaching

将该注解放在配置类上开启缓存,使用该注解后,允许你指定各种选项,通过AOP的方式把这些影响添加到你的应用程序中. 类似于 @Transactional

1.2@Cacheable

触发数据存储于缓存

顾名思义,@Cacheable用于标示可缓存的方法 - 即将结果存储到缓存中的方法,以便在后续调用(具有相同的参数)时,返回缓存中的值而不必实际执行该方法.

下图是所有的缓存的存储结构

cacheNames:指定缓存的名称,不同缓存的数据是彼此隔离的,可以指定多个缓存名称.(就是生成多个缓存name).如果有一个缓存命中,关联值就会返回.

更新一个name的缓存,其他所有没有包含这个值的缓存也会被更新,即使这个缓存方法没有实际调用.

@Cacheable({"coffees","coffees2"})
public List<Coffee> findAllCoffee() {
return coffeeRepository.findAll();

}

1.2.1默认key生成规则

Key :

上面cacheNames指定了缓存名称,但是每个方法由于传参不同,其return数据也会不同,所以一个方法中可能会有多个缓存。要在同一个cacheNames中区别不同的缓存,就需要使用key。通过SPEL表达式,指定 name为key。Spring 会默认以参数为key 如果没有参数则有一个org.springframework.cache.interceptor.SimpleKey.

@Cacheable(cacheNames = "coffees",key = "#name")
public Optional<Coffee> findOneCoffee(String name) {
ExampleMatcher matcher = ExampleMatcher.matching()
.withMatcher("name", exact().ignoreCase());
Optional<Coffee> coffee = coffeeRepository.findOne(
Example.of(Coffee.builder().name(name).build(), matcher));
log.info("Coffee Found: {}", coffee);
return coffee;
}

因为Caches是一个key-value的存储形式,每次调用缓存方法需要翻译成对应的key来访问缓存。缓存抽象使用简单的 keygenerator 基于以下算法:

  • 如果没有参数,返回SimpleKey.EMPTY.
  • 如果只有一个参数,就会作为实例返回.
  • 如果超过一个参数,就会返回包含所有参数的 SimpleKey.

该方法对大多数case有效,只要参数有nautral keys并且他们有效的实现了 hashcode()和equals()方法.如果不是这个case的需要去改变策略.

提供不同的key 生成器,需要去实现 org.springframework.cache.interceptor.KeyGenerator 这个接口.

默认的key生成策略在spring 4.0以后有所改变.之前的Spring版本使用用的key生成策略,对于多个key参数,仅用参数的hashCode()没有使用equeal().这可能造成key冲突(从 SPR-10237查看背景).新的 SimpleKeyGenerator对于这种场景使用了组合key.

如果你想保持之前的key生成策略,你可以配置不推荐使用的org.springframework.cache.interceptor.DefaultKeyGenerator或者创建一个自定义的 基于hash的 key产生的实现

1.2.2声明自定义key 生成

因为缓存是通用的,所以目标方法很可能有多种写法,这些不能够被顶层缓存结构简单的映射.当一个方法有多个参数,但只有一些参数需要缓存时(其他key只给方法使用),这一点变得很明显.

@Cacheable("books")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

上面的例子: 用到了两个布尔参数,他们对缓存可能没有用处,此外如果有一个有用另一个没用应该怎么办?

上面说过我们可以通过@Cacheable 来指定key通过哪些参数生成.可以使用SPEL来选择感兴趣的参数(以及嵌套属性),执行操作,或者甚至调用任意方法都可以不需要写任何代码或者实现任何接口. 推荐的默认的key 产生方式在上面已经说过,但是默认的策略并不能适应所有的方法.

下面例子使用了多种SPEL语法:

@Cacheable(cacheNames="books", key="#isbn")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
@Cacheable(cacheNames="books", key="#isbn.rawNumber")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
@Cacheable(cacheNames="books", key="T(someType).hash(#isbn)")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

如果生成key的算法太过特殊或者需要共享,可以自定义keyGenerator.

@Cacheable(cacheNames="books", keyGenerator="myKeyGenerator")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

注: key 和 keyGenerator是互斥的,同时指定会产生异常

1.2.3默认的cache resolution

默认的cache resolution是一个简单的 CacheResolver ,通过配置CacheManager来检索在操作级别定义的缓存.
通过继承实现org.springframework.cache.interceptor.CacheResolver 接口来提供不同的默认resolver.
默认的cache resolution是由单个CacheManager实现并且没有太复杂的resolution的需求.
默认的cache resolution是由单个CacheManager实现并且没有太复杂的resolution的需求.
当一个应用同时使用多个 cacheManager 可以通过cachemanager指定

@Cacheable(cacheNames="books", cacheManager="anotherCacheManager")
public Book findBook(ISBN isbn) {...}

也可以通过cacheResolver替换resolver 类似于替换key generation.

@Cacheable(cacheResolver="runtimeCacheResolver")
public Book findBook(ISBN isbn) {...}

这个resolution在每次缓存操作都会请求,允许我们基于实时的参数来实现解析缓存.

从spring 4.1之后, value的属性不再强制要求传,因为无论annotation的内容传什么,这个特定信息都会被CacheResolver提供.

类似于key和keygenerator,cacheManager和cahceResolver这两个参数都是互斥的,同时指定会返回异常,因为定义的cacheManager会被定义的cacheResolver的实现给忽略.

1.2.4同步缓存

在多线程环境里,某些操作可能使用相同参数并发调用(典型的例如启动).默认情况下,缓存抽象不会加锁,如果一个同样的值多次被计算是违背缓存的初衷的.

在这种特殊的情况下,可以使用 sync 属性来指定缓存提供方在计算缓存实体的时候加锁.

@Cacheable(cacheNames="foos", sync=true)
public Foo executeExpensiveOperation(String id) {...}

这个可选特性,也许提供缓存的库并不支持.所有的 核心框架提供得CacheManager是支持的.

1.2.5 缓存的条件

有时,一个方法并不能在所有时候都适用于一个缓存(比如,它可能依赖于给定参数).缓存的注解支持这些情况,通过使用 condition 参数.

condition中使用 Spel 表达式可以得出 true 或者false.如果是true,方法缓存,反之,方法不会缓存(这个方法无论什么值或者使用任何参数都会被调用).

@Cacheable(cacheNames="book", condition="#name.length() < 32")
public Book findBook(String name)

1.上面设置的条件是name的长度 小于32

@Cacheable(cacheNames="book", condition="#name.length() < 32", unless="#result.hardback")
public Book findBook(String name)

2.使用unless, 否决掉对应的value到缓存中.不像condition,unless表达式是在方法调用完后被调用,上面的例子就是如果我们只想缓存paperback book, 我们可以阻挡 hardback.

缓存抽象同样支持 java.util.Optional,返回类型.如果Optional是present,则被关联到对应缓存,如果not present,将会存储一个null. #result 总是引用业务对象并且永远不会支持包装器,所以上面的例子可以改为

@Cacheable(cacheNames="book", condition="#name.length() < 32", unless="#result?.hardback")
public Optional<Book> findBook(String name)

上面的例子 #result一直引用Book 而不是Optional<Book>.因为有可能为空,所以使用SpEL's的Safe Navigation Operator

1.2.6可用的Spel 评估上下文


名称


位置


描述


例子


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


任何方法参数的名称.如果名称找不到(也许是没有debug信息),这个参数名称可能在#a<#arg>之下找到, 这个#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 表达式(当 beforeInvocation=false)可用. 为了支持wrappers(比如 Optional),#result 引用的实际的对象而非 wrapper


#result

以上就是spring框架cacheAnnotation注释声明缓存解析的详细内容,更多关于spring框架cache缓存Annotation注释的资料请关注我们其它相关文章!

(0)

相关推荐

  • Spring Cache的基本使用与实现原理详解

    Spring Cache 概念 从Spring 3.1版本开始,提供了一种透明的方式来为现有的Spring 应用添加cache,使用起来就像@Transaction一样.在应用层面与后端存储之间,提供了一层抽象,这层抽象目的在于封装各种可插拔的后端存储( Ehcache Guava Redis),最小化因为缓存给现有业务代码带来的侵入. Spring 的缓存技术还具备相当的灵活性.不仅能够使用 SpEL(Spring Expression Language)来定义缓存的 key 和各种 cond

  • 使用Spring Cache设置缓存条件操作

    目录 Spring Cache设置缓存条件 原理 @Cacheable的常用属性及说明 Root对象 @CachePut的常用属性同@Cacheable Cache缓存配置 1.pom.xml 2.Ehcache配置文件 3.配置类 4.示例 Spring Cache设置缓存条件 原理 从Spring3.1开始,Spring框架提供了对Cache的支持,提供了一个对缓存使用的抽象,通过在既有代码中添加少量它定义的各种 annotation,即能够达到缓存方法的返回对象的作用. 提供的主要注解有@

  • Spring实战之类级别缓存实现与使用方法

    本文实例讲述了Spring实战之类级别缓存实现与使用方法.分享给大家供大家参考,具体如下: 一 配置文件 <?xml version="1.0" encoding="GBK"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xml

  • Spring Boot 中使用cache缓存的方法

    一.什么是缓存 Cache Cache 一词最早来自于CPU设计 当CPU要读取一个数据时,首先从CPU缓存中查找,找到就立即读取并送给CPU处理:没有找到,就从速率相对较慢的内存中读取并送给CPU处理,同时把这个数据所在的数据块调入缓存中,可以使得以后对整块数据的读取都从缓存中进行,不必再调用内存.正是这样的读取机制使CPU读取缓存的命中率非常高(大多数CPU可达90%左右),也就是说CPU下一次要读取的数据90%都在CPU缓存中,只有大约10%需要从内存读取.这大大节省了CPU直接读取内存的

  • 深入理解Spring Cache框架

    本文是缓存系列第三篇,前两篇分别介绍了 Guava 和 JetCache. 前两篇我们讲了 Guava 和 JetCache,它们都是缓存的具体实现,今天给大家分析一下 Spring 框架本身对这些缓存具体实现的支持和融合.使用 Spring Cache 将大大的减少我们的Spring项目中缓存使用的复杂度,提高代码可读性.本文将从以下几个方面来认识Spring Cache框架. 背景 SpringCache 产生的背景其实与Spring产生的背景有点类似.由于 Java EE 系统框架臃肿.低

  • spring框架cacheAnnotation缓存注释声明解析

    目录 1.基于注释声明缓存 1.1@EnableCaching 1.2@Cacheable 1.2.1默认key生成规则 1.2.2声明自定义key 生成 1.2.3默认的cache resolution 1.2.4同步缓存 1.2.5 缓存的条件 1.2.6可用的Spel 评估上下文 1.基于注释声明缓存 声明缓存,Spring缓存抽象提供了一个java annotation集合. @Cacheable:触发缓存填充. @CacheEvict: 触发缓存删除. @CachePut: 不干扰方法

  • 解析Java的Spring框架的基本结构

    在java届,有位名叫Rod Johnson的牛人,发现最初的java企业级开发处于混沌状态. 于是,它决心编写一个能够解决问题的通用的基础架构. 因为它深信面向接口编程能够将变化控制到最小,同时也利于扩展和变化.于是,它编写了如下的接口. 在混沌状态最先要创造的是一切对象的母亲BeanFactory,有了它,就能够得到一切它孕育的对象和属性,也就是说首先要造盖亚--大地之母. 有了最初的母亲BeanFactory,johnson想,如果我要得到一组Bean对象而不单单是某个或某几个呢?另外,如

  • 深入解析Java的Spring框架中bean的依赖注入

    每一个基于java的应用程序都有一个共同工作来展示给用户看到的内容作为工作的应用几个对象.当编写一个复杂的Java应用程序,应用程序类应该尽可能独立其他Java类来增加重复使用这些类,并独立于其他类别的测试它们,而这样做单元测试的可能性.依赖注入(或有时称为布线)有助于粘合这些类在一起,同时保持他们的独立. 考虑有其中有一个文本编辑器组件的应用程序,要提供拼写检查.标准的代码将看起来像这样: public class TextEditor { private SpellChecker spell

  • Spring框架初始化解析

    一.Spring能做什么? Spring的主要目的是使J2EE易用和促进好编程习惯. 倒置控制容器 Spring的设计核心是 org.springframework.beans 包, 为与JavaBeans一起工作而设计. 这个包一般不直接被用户使用, 但作为基础为更多的其他功能服务. 下一个较高层面的抽象是"Bean Factory". Spring bean factory 是一个普通的Factory,它使对象能够按名称获取,并且能管理对象之间的关系. Bean factories

  • Spring框架接入单机Redis两种实现方式解析

    1.Redis的简单介绍 1)Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库.缓存和消息中间件. 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询. 这些数据类型都支持push/pop.add/remove及取交集并集和差集及更丰富的操作,而且

  • Spring框架基于AOP实现简单日志管理步骤解析

    SPringAOP的使用 技术概述,描述这个技术是做什么?学习该技术的原因,技术的难点在哪里. 为了实现项目管理员端的操作数据库日志,便于方便所以利用Spring框架的AOP机制进行实现,项目的难点在于如果设置切入点,如何获取参数. 技术详述,描述你是如何实现和使用该技术的,要求配合代码和流程图详细描述.可以再细分多个点,分开描述各个部分. 在applicationContext.xml中开启AOP代理 <aop:aspectj-autoproxy /> 自定义一个注解 @Target(Ele

  • Spring框架中 @Autowired 和 @Resource 注解的区别

    Spring框架中 @Autowired 和 @Resource 注解的区别 在 spring 框架中,除了使用其特有的注解外,使用基于 JSR-250 的注解,它包括 @PostConstruct, @PreDestroy 和 @Resource 注释. 首先,咱们简单了解 @PostConstruct 和 @PreDestroy 注释: 为了定义一个 bean 的安装和卸载,我们可以使用 init-method 和 destroy-method 参数简单的声明一下 ,其中 init-meth

  • Spring框架web项目实战全代码分享

    以下是一个最简单的示例 1.新建一个标准的javaweb项目 2.导入spring所需的一些基本的jar包 3.配置web.xml文件 <?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/

  • spring框架学习总结

    目录 Spring 框架概述 Spring优点 Spring体系结构 Spring拓展 Spring Boot与Spring Cloud Spring IoC 容器 (IoC 也称为依赖项注入(DI),或DI是实现IoC的一种方法) IoC容器概述 Spring入门程序 IoC创建对象的三种方式 通过无参构造(要提供set方法) 通过有参构造(要提供get方法) 通过工厂类 Spring依赖注入(DI)和Bean的作用域 Spring 常用配置及属性 Spring自动装配 Spring注解开发

  • Spring框架学习之Cache抽象详解

    目录 1.简介 cache和buffer 2.缓存抽象 3.spring缓存抽象与多进程 官方文档  8.0 Spring为不同缓存做了一层抽象,这里通过阅读文档以及源码会对使用以及原理做一些学习笔记. 1.简介 从3.1版开始,Spring Framework提供了对现有Spring应用程序透明地添加缓存的支持. 与事务支持类似,缓存抽象允许一致地使用各种缓存解决方案,而对代码的影响最小. 从Spring 4.1开始,通过JSR-107注释和更多自定义选项的支持,缓存抽象得到了显着改进. ca

随机推荐