spring 请求转码_Spring请求级备忘录

spring 请求转码

介绍

备注化是一种方法级别的缓存技术,用于加快连续调用的速度。

这篇文章将演示如何仅使用Spring AOP实现任何数据源的请求级可重复读取。

Spring缓存

Spring提供了非常有用的缓存抽象 ,允许您将应用程序逻辑与缓存实现细节分离。

Spring Caching使用应用程序级范围,因此对于仅请求的备忘录,我们需要采用DIY方法。

请求级缓存

请求级缓存条目生命周期始终绑定到当前请求范围。 这样的缓存与提供会话级可重复读取的 Hibernate Persistence Context非常相似。

为了防止更新丢失 ,甚至对于NoSQL解决方案,必须进行可重复的读取 。

分步实施

首先,我们将定义一个“记忆标记”注释:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Memoize {
}

该注释将显式标记所有需要记住的方法。

为了区分不同的方法调用,我们将方法调用信息封装为以下对象类型:

public class InvocationContext {public static final String TEMPLATE = "%s.%s(%s)";private final Class targetClass;private final String targetMethod;private final Object[] args;public InvocationContext(Class targetClass, String targetMethod, Object[] args) {this.targetClass = targetClass;this.targetMethod = targetMethod;this.args = args;}public Class getTargetClass() {return targetClass;}public String getTargetMethod() {return targetMethod;}public Object[] getArgs() {return args;}@Overridepublic boolean equals(Object that) {return EqualsBuilder.reflectionEquals(this, that);}@Overridepublic int hashCode() {return HashCodeBuilder.reflectionHashCode(this);}@Overridepublic String toString() {return String.format(TEMPLATE, targetClass.getName(), targetMethod, Arrays.toString(args));}
}

很少有人知道Spring Request / Session bean的作用域。

因为我们需要一个请求级的备忘录作用域,所以我们可以使用Spring请求范围来简化我们的设计,该作用域隐藏了实际的HttpSession解析逻辑:

@Component
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS, value = "request")
public class RequestScopeCache {public static final Object NONE = new Object();private final Map<InvocationContext, Object> cache = new HashMap<InvocationContext, Object>();public Object get(InvocationContext invocationContext) {return cache.containsKey(invocationContext) ? cache.get(invocationContext) : NONE;}public void put(InvocationContext methodInvocation, Object result) {cache.put(methodInvocation, result);}
}

由于没有运行时处理引擎,仅注释就没有任何意义,因此,我们必须定义一个实现实际备注逻辑的Spring Aspect:

@Aspect
public class MemoizerAspect {@Autowiredprivate RequestScopeCache requestScopeCache;@Around("@annotation(com.vladmihalcea.cache.Memoize)")public Object memoize(ProceedingJoinPoint pjp) throws Throwable {InvocationContext invocationContext = new InvocationContext(pjp.getSignature().getDeclaringType(),pjp.getSignature().getName(),pjp.getArgs());Object result = requestScopeCache.get(invocationContext);if (RequestScopeCache.NONE == result) {result = pjp.proceed();LOGGER.info("Memoizing result {}, for method invocation: {}", result, invocationContext);requestScopeCache.put(invocationContext, result);} else {LOGGER.info("Using memoized result: {}, for method invocation: {}", result, invocationContext);}return result;}
}

测试时间

让我们对所有这些进行测试。 为简单起见,我们将使用Fibonacci数字计算器模拟请求级范围的备忘需求:

@Component
public class FibonacciServiceImpl implements FibonacciService {@Autowiredprivate ApplicationContext applicationContext;private FibonacciService fibonacciService;@PostConstructprivate void init() {fibonacciService = applicationContext.getBean(FibonacciService.class);}@Memoizepublic int compute(int i) {LOGGER.info("Calculate fibonacci for number {}", i);if (i == 0 || i == 1)return i;return fibonacciService.compute(i - 2) + fibonacciService.compute(i - 1);}
}

如果要计算第十个斐波那契数,我们将得到以下结果:

Calculate fibonacci for number 10
Calculate fibonacci for number 8
Calculate fibonacci for number 6
Calculate fibonacci for number 4
Calculate fibonacci for number 2
Calculate fibonacci for number 0
Memoizing result 0, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([0])
Calculate fibonacci for number 1
Memoizing result 1, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([1])
Memoizing result 1, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([2])
Calculate fibonacci for number 3
Using memoized result: 1, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([1])
Using memoized result: 1, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([2])
Memoizing result 2, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([3])
Memoizing result 3, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([4])
Calculate fibonacci for number 5
Using memoized result: 2, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([3])
Using memoized result: 3, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([4])
Memoizing result 5, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([5])
Memoizing result 8, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([6])
Calculate fibonacci for number 7
Using memoized result: 5, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([5])
Using memoized result: 8, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([6])
Memoizing result 13, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([7])
Memoizing result 21, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([8])
Calculate fibonacci for number 9
Using memoized result: 13, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([7])
Using memoized result: 21, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([8])
Memoizing result 34, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([9])
Memoizing result 55, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([10])

结论

记忆是一个贯穿各领域的问题,Spring AOP允许您将缓存详细信息与实际的应用程序逻辑代码分离。

  • 代码可在GitHub上获得 。

翻译自: https://www.javacodegeeks.com/2014/12/spring-request-level-memoization.html

spring 请求转码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/338949.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java map 如何根据key获得对象_ThreadLocal:Java中的影分身

关于ThreadLocal&#xff0c;你有哪些疑问&#xff1f;ThreadLocal是用来解决什么问题的&#xff1f;如何使用ThreadLocal&#xff1f;ThreadLocal的实现原理是什么&#xff1f;可否举几个实际项目中使用ThreadLocal的案例&#xff1f;基础知识ThreadLocal是线程局部变量&#…

【C语言】你可能对 sizeof() 有点误解。。。

各位&#xff0c;今天还是按照惯例给大家分享一个C语言容易出现的小错误&#xff0c;这也是跟sizeof有关的&#xff0c;问题虽小&#xff0c;却可管中窥豹&#xff0c;话不多说&#xff0c;代码先行&#xff1a;#include int main() { int i; i 8; printf("%d\…

mysql cluster 设置单向复制_mysql单向主从配置

1.环境要求操作系统&#xff1a;centOS6.5或以上Mysql版本&#xff1a;mysql5.5主机配置&#xff1a;4核CPU、4G内存2.主从复制的方式mysql5.6开始主从复制有两种方式&#xff1a;基于日志(binlog)、基于GTID(全局十事务标示符)&#xff0c;下面主要介绍基于日志(binlog)的复制…

java处理注释_如何处理Java注释

java处理注释Java 8的一项很酷的新功能是对lambda表达式的支持。 Lambda表达式在很大程度上依赖于FunctionalInterface 注释 。 在本文中&#xff0c;我们将介绍注释以及如何处理它们&#xff0c;以便您可以实现自己的出色功能。 注解 Java 5中添加了注释 。Java语言附带了一…

nginx tcp转发_Nginx学习(九):负载均衡服务

介绍对于请求而言&#xff0c;负载均衡能很好的均摊请求&#xff0c;提高服务端吞吐率和整体性能&#xff0c;多个服务节点部署的方式&#xff0c;也提高了容灾和服务高可用。一、负载均衡分类负载均衡分为&#xff1a;GSLB和SLB。1. GDLB全局负载均衡&#xff0c;往往按照国家…

控制台发送get命令_.NET Core使用命令行参数库构建控制台应用程序

前言在我们开发中可能需要设计一次性应用程序&#xff0c;这些实用程序可以利用接近原始源代码的优势&#xff0c;但可以在与主Web应用程序完全独立的安全性上下文中启动。具体在 [管理过程](https://12factor.net/admin-processes)中也已经列出了原因。创建控制台应用打开命令…

C语言函数为什么不能返回数组?

C语言函数为什么不能返回数组&#xff1f;在C语言程序开发中&#xff0c;我们不可以编写下面这样的代码&#xff1a;char f(void)[8] {char ret; // ...fill... return ret; }int main(int argc, char ** argv) {char obj_a[10]; obj_a f(); }不可以编写这样的代码这其实就是不…

mockito_书评:Mockito Essentials

mockitoSujoy Acharya的Mockito Essentials副标题&#xff08; Packt出版 &#xff0c;2014年10月&#xff09;是&#xff1a;“实用指南&#xff0c;可帮助您使用Mockito进行单元测试并开始运行。” Mockito Essentials中的前言和七章涵盖大约190个实质性页面。 前言 在序言中…

python3 byte 字面值_bytearray() Python 内置函数

转载须注明出处&#xff1a;简书Orca_J35 | GitHuborca-j35 class bytearray([source[, encoding[, errors]]]) 该内置函数本质上是 bytearray 类的构造函数&#xff0c;用于创建一个 bytearray 实例。bytearray 实例是一个由字节(8-bits 无符号)构成的可变序列&#xff0c;并拥…

python如何调用c函数实现真正意义的多线程_python如何使用多线程执行多个函数?...

之前小编给大家介绍了用python去返回了一个值&#xff0c;立马就有小伙伴跟小编留言说道“能都执行多个内容&#xff1f;”于是&#xff0c;小编就给大家整理最细致&#xff0c;也是最简单的实现方法&#xff0c;方便大家理解学习&#xff0c;一起来看下吧~直接上代码&#xff…

Java EE 8怎么了? (第2部分)

Java EE 8的工作仍处于初期阶段&#xff0c;并有望在来年跟上发展步伐&#xff0c;届时我们将看到专家组的完成&#xff0c;围绕用例/功能的更多讨论&#xff0c;大量JIRA和各种规范的草案版本&#xff08;本会很有趣&#xff01;&#xff09;。 在第1部分中 &#xff0c;我们…

C语言中quot;##quot;的独特用法

市面上有很多比较火的编程语言&#xff0c;比如Python、 JAVA、 Go等&#xff0c;你可能觉得C语言很古老、很落后。如果你有这种想法&#xff0c;那可能你只是一个初学的菜鸟。可能绝大部分 C 程序员都不知道"##"隐藏用法&#xff0c;下面就来给大家讲讲。一、##的“…

html a标签去掉下划线_如何用HTML基本元素制作表格

第2天【HTML基本元素】主要内容标题标签段落标签强制换行水平线图片超链接文本格式化标签列表表格学习目标一、标题标题&#xff08;Heading&#xff09;是通过 <h1> - <h6> 标签进行定义的。<h1> 定义最大的标题。 <h6> 定义最小的标题。标题很重要请…

mysql忽略数据类型_MYSQL 常用数据类型

数字列类型数字列类型用于储存各种数字数据&#xff0c;如价格、年龄或者数量。数字列类型主要分为两种&#xff1a;整数型和浮点型。所有的数字列类型都允许有两个选项&#xff1a;UNSIGNED和ZEROFILL。选择UNSIGNED的列不允许有负数&#xff0c;选择了ZEROFILL的列会为数值添…

C语言中几个容易踩的“坑”!

今天给大家分享几个C语言中的坑。一、带参数的宏展开顺序#include #define f(a,b) a##b #define g(a) #a #define h(a) g(a)int main(void) {printf("%s\n",h(f(1,2)));printf("%s\n",g(f(1,2)));return 0; }运行结果:12f(1,2)浅析&#xff1a;本题中的#运…

java 拼图_我最喜欢的Java拼图2 + 1 = 4

java 拼图这是我当前最喜欢的Java难题。 您如何获取代码来执行此操作&#xff1f; Integer b 2; Integer c 1;System.out.println("bc : " (bc) ); // output: bc : 4 !!Sytem.out.println&#xff08;&#xff09;没有技巧&#xff0c;也就是说&#xff0c;您将…

dockerfile cd目录_使用Werf和现有的Dockerfiles改善你的CI/CD体验

迟到总比不到好。该故事讲关于我们因不支持使用常规的Dockerfile来构建镜像导致我们差点犯了一个重大错误。Werf[1]是一个GitOps工具&#xff0c;可以很好地集成到任何CI/CD系统中&#xff0c;并提供完整的应用程序生命周期管理&#xff0c;允许你&#xff1a;构建和推送镜像部…

alxc tool 报错数组超出了界限_代码审计之报错信息泄露与字符串截断

机器在语言编码转换的时候&#xff0c;经常会出现各种各样的异常&#xff0c;这些神奇的字符串就有可能组合成一堆乱码出来&#xff0c;也有可能直接把程序搞崩溃掉&#xff0c;不过总有那么一些字符&#xff0c;可以帮助我们在利用漏洞的时候变得更简单一些&#xff0c;下面我…

C语言,去你的策略模式!

前言 这里先插一点题外话&#xff0c;在C语言中&#xff0c;实现封装、继承、隐藏、多态等等特性&#xff0c;是完全没有问题的。但是在使用过程中&#xff0c;必定是不如自带这些特性的语言方便好用的&#xff0c;比如C \java等。一旦要通过C语言来实现各种设计模式&#xff0…

eager_EAGER的获取是代码的味道

eager介绍 Hibernate获取策略确实可以使几乎没有爬网的应用程序和响应Swift的应用程序有所不同。 在这篇文章中&#xff0c;我将解释为什么您应该选择基于查询的获取而不是全局获取计划。 取得101 Hibernate定义了四种关联检索策略 &#xff1a; 提取策略 描述 加入 原始S…