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

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

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

相关文章

从一个帖子看 所谓“知乎” 的真实水平

帖子地址&#xff1a;https://www.zhihu.com/question/27535713 明末尤其是崇祯后期&#xff0c;最大的背景是天灾瘟疫反复肆虐&#xff0c;三成人死于饥荒&#xff0c;三成人死于瘟疫&#xff0c;四成为生存从贼是当时中原的真实写照。 抛开这个最大前提不谈&#xff0c;去乱弹…

新的开始,新的挑战

我承认&#xff0c;我还比较年轻&#xff0c;我承认&#xff0c;我的经验很少&#xff0c;我承认&#xff0c;我的能力还是比较小。。。。。。 但是&#xff0c;我不怕&#xff0c;我敢往前走&#xff0c;错了我就改&#xff0c;不行我就努力&#xff0c; 要么痛苦的坚持到游戏…

响应式布局笔记

一. 布局设计 固定布局&#xff1a;以像素作为页面的基本单位&#xff0c;不管设备屏幕及浏览器宽度&#xff0c;只设计一套尺寸&#xff1b; 可切换的固定布局&#xff1a;同样以像素作为页面单位&#xff0c;参考主流设备尺寸&#xff0c;设计几套不同宽度的布局。通过设别的…

麦冬

麦冬 中文学名&#xff1a;麦冬 拉丁学名&#xff1a;Ophiopogon japonicus (Linn. f.) Ker-Gawl. 别称&#xff1a;麦门冬、沿阶草 植物界百合科 主要价值&#xff1a; 1、有养阴润肺、益胃生津、清心除烦的功效&#xff0c;用于肺燥干咳、阴虚痨嗽、喉痹咽痛、津伤口渴、…

如何使用Callable和FutureTask

介绍 从Java 1.5开始&#xff0c;在java.util.concurrent下有了新的对象集。 该程序包具有许多不同的类&#xff0c;包括线程队列。 当我用Java 1.2编程时&#xff0c;我本可以使用那些&#xff01; 当我开始看这些新玩具时&#xff0c;我变得犹豫不决。 这是什么可调用的东西&…

NodeJS的安装与使用

Node.js 就是运行在服务端的 JavaScript。越来越多的人在使用它&#xff0c;通过他我们可以用JavaScript来构建后台。对于前端程序员而言&#xff0c;不言而喻这是一条多么令人振奋的消息。对于后台程序员而言&#xff0c;这也是一种很不错的选择。 下面我就来讲解下nodejs的安…

转载 300年前的黑色“巫女”

1741年&#xff0c;北极。 白令招呼水手们把船靠上小岛的时候&#xff0c;一排黑色的鸬鹚站在陡峭的悬崖上&#xff0c;像一群黑色的巫女&#xff0c;一动不动朝着他们张望。白令顿时有了一种不祥的预兆。 果然&#xff0c;刚刚上岛&#xff0c;就遭到古怪的兰狐的袭击&#xf…

华为在爱尔兰增设150个LTE研发职位

据国外媒体报道中国电信和网络跨国公司华为技术预计将在未来两年内在爱尔兰增设150个职位。华为公司目前设在爱尔兰都柏林、阿斯隆和科克的业务处共有50名员工。现在&#xff0c;公司已经投标竞购牌照&#xff0c;目的是为在爱尔兰推出第四代宽带进行基础设施开发。华为公司爱尔…

Java EE 7 / JAX-RS 2.0 – REST上的CORS

Java EE REST应用程序通常在开箱即用的开发机器上运行良好&#xff0c;该开发机器上所有服务器端资源和客户端UI均指向“ localhost”或127.0.0.1。 但是&#xff0c;当涉及跨域部署时&#xff08;当REST客户端不再与托管REST API的服务器位于同一域时&#xff09;&#xff0c;…

jQuery框架-1.jQuery基础知识

jQuery简介 jQuery&#xff0c;顾名思义是JavaScript和查询&#xff08;Query&#xff09;&#xff0c;jQuery是免费、开源的。它可以简化查询DOM对象、处理事件、制作动画、处理Ajax交互过程且兼容多浏览器的javascript库&#xff0c;核心理念是write less,do more(写得更少,…

用CornerStone配置SVN,HTTP及svn简单使用说明

原文地址&#xff1a;&#xff1a;&#xff1a;http://my.oschina.net/joanfen/blog/194491#OSC_h2_3 一、下载地址二、安装破解方法三、添加repository 1.SVN配置 2.HTTP配置四、使用简介 1.上传项目到repository 2.下载项目 3.版本管理 a)先更新后提交 b)完成独立功…

联系随笔2---在tomcat服务器上发布servlet应用程序

问题二&#xff1a;在tomcat服务器上发布servlet应用程序 1,new->Dynamic Web Project写工程名字->next->next在Generate web.xml文件上打勾勾->finish. 2&#xff0c;在工程名字上&#xff0c;new->servlet。在create Servlet对话框中填写java package包名字和…

Apache Lucene 5.0.0即将发布!

终于&#xff0c;在一系列强大的4.x功能&#xff08;最近是4.10.2&#xff09;发布之后&#xff0c;我们终于在努力开发另一个主要的Apache Lucene版本&#xff01; 没有确切时间的承诺&#xff08;完成时就完成了&#xff01;&#xff09;&#xff0c;但是我们已经有一个自愿…

从零开始学习前端开发 — 15、CSS3过渡、动画

一、css3过渡 语法&#xff1a; transition: 过渡属性 过渡时间 延迟时间 过渡方式; 1.过渡属性(transition-property) 取值&#xff1a;all 所有发生变化的css属性都添加过渡 eg: transition: all 1s; ident 指定要过渡的css属性列表 eg: transition:border-radius 1s,back…

CentOS6.4 Install FTP

目录 安装参考传输模式遇到无法显示远程文件夹报错安装参考 https://www.cnblogs.com/walblog/articles/7890226.html 传输模式 主动模式被动模式遇到无法显示远程文件夹报错 点击属性设置&#xff1a; 搞定。 转载于:https://www.cnblogs.com/mysticbinary/articles/11271647.…

windowsphone7高级编程中提到的地址

1、综合性技术论坛&#xff0c;包括windowsphone,.net,iphone,android等&#xff0c;网址&#xff1a;http://p2p.wrox.com 2、windowsphone7高级编程作者Nick Randolph发表博客的网站&#xff0c;网址&#xff1a;http://www.christec.co.nz/&#xff0c; 书中代码下载地址&am…

用于单元测试的JUnit教程–最终指南(PDF下载)

编者注&#xff1a; 我们在Java Code Geeks上提供了许多JUnit教程&#xff0c;例如JUnit入门示例 &#xff0c; 使用断言和注释的 JUnit 示例 &#xff0c; JUnit注释示例等。 但是&#xff0c;为了方便读者&#xff0c;我们希望将所有JUnit功能收集在一份详细的指南中。 我们…

EF 拉姆达 linq if else (整理)

首先想到&#xff1a;结果不正确&#xff01; var data0 db.T_Plants2; //这里加.AsQueryable()if (locationType 1){.Where(d > d.NaturalEcosystem true);}else{.Where(d > d.BuiltUpArea true);}.Select(d > new{AnimalID d.PlantID,Species d.Species,}).To…

从零开始学习前端开发 — 7、CSS宽高自适应

一、宽度自适应 语法&#xff1a;width:100%; 注&#xff1a; a&#xff09;块状元素的默认宽度为100% b) 当给元素设置宽度为100%时&#xff0c;继承父元素的宽度 c) 通常使用宽度自适应实现通栏效果 二、高度自适应 语法&#xff1a;height:auto;&#xff08;等同于不给元…

用jOOQ用Java编写SQL

jOOQ是“数据库优先”的类型安全的SQL API&#xff0c;使您可以直观地用Java编写SQL&#xff0c;就像Java编译器本身支持SQL语言一样。 所有数据库模式&#xff0c;表&#xff0c;列&#xff0c;过程和其他对象均作为Java对象提供&#xff0c;可以直接在jOOQ SQL API中使用。 …