guava的正确引入方式_使用Guava的AbstractInvocationHandler正确完成代理

guava的正确引入方式

不太经常,但有时我们被迫使用java.lang.reflect.Proxy编写自定义动态代理类 。 这种机制实际上没有任何魔术,即使您永远不会真正使用它,也值得知道–因为Java代理在各种框架和库中无处不在。

这个想法很简单:动态创建一个实现一个或多个接口的对象,但是每次调用这些接口的任何方法时,都会调用我们的自定义回调处理程序。 该处理程序接收到一个被称为( java.lang.reflect.Method实例)方法的句柄,并且可以以任何方式自由执行。 代理通常用于实现无缝的模拟,缓存,事务和安全性-即它们是AOP的基础。

在我从标题解释com.google.common.reflect.AbstractInvocationHandler的目的之前,让我们从一个简单的示例开始。 假设我们要在线程池中异步透明地运行给定接口的方法。 像Spring(参见: 27.4.3 The @Async Annotation )和Java EE(参见: Asynchronous Method Invocation )之类的流行堆栈已经使用相同的技术来支持此功能。

假设我们提供以下服务:

public interface MailServer {void send(String msg);int unreadCount();
}

我们的目标是异步运行send()以便几个后续调用不会阻塞而是排队,并在外部线程池中同时执行,而不是在调用线程中执行。 首先,我们需要将创建代理实例的工厂代码:

public class  AsyncProxy {public static <T> T wrap(T underlying, ExecutorService pool) {final ClassLoader classLoader = underlying.getClass().getClassLoader();final Class<T> intf = (Class<T>) underlying.getClass().getInterfaces()[0];return (T)Proxy.newProxyInstance(classLoader,new Class<?>[] {intf},new AsyncHandler<T>(underlying, pool));}
}

上面的代码做出了一些大胆的假设,例如,一个underlying对象(我们正在代理的真实实例)恰好实现了一个接口。 在现实生活中,一门课程当然可以实现多个接口,代理也可以实现多个接口,但是出于教育目的,我们对此进行了一些简化。 现在,对于初学者,我们将创建无操作代理,该代理将委托给基础对象而没有任何附加值:

class AsyncHandler<T> implements InvocationHandler {private static final Logger log = LoggerFactory.getLogger(AsyncHandler.class);private final T underlying;private final ExecutorService pool;AsyncHandler1(T underlying, ExecutorService pool) {this.underlying = underlying;this.pool = pool;}@Overridepublic Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable {return method.invoke(underlying, args);}}

ExecutorService pool将在以后使用。 最后一行至关重要–我们在具有相同args underlying实例上调用method 。 在这一点上,我们可以:

  • 是否调用underlying (例如,如果给定的呼叫被缓存/存储)
  • 更改参数(即出于安全目的)
  • 在异常之前/之后/周围/上运行代码
  • 通过返回不同的值来改变结果(它必须与method.getReturnType()的类型匹配)
  • …以及更多

在我们的例子中,我们将method.invoke()Callable包装在一起,并异步运行它:

class AsyncHandler<T> implements InvocationHandler {private final T underlying;private final ExecutorService pool;AsyncHandler(T underlying, ExecutorService pool) {this.underlying = underlying;this.pool = pool;}@Overridepublic Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable {final Future<Object> future = pool.submit(new Callable<Object>() {@Overridepublic Object call() throws Exception {return method.invoke(underlying, args);}});return handleResult(method, future);}private Object handleResult(Method method, Future<Object> future) throws Throwable {if (method.getReturnType() == void.class)return null;try {return future.get();} catch (ExecutionException e) {throw e.getCause();}}
}

提取了额外的handleResult()方法以正确处理非void方法。 使用这样的代理很简单:

final MailServer mailServer = new RealMailServer();final ExecutorService pool = Executors.newFixedThreadPool(10);
final MailServer asyncMailServer = AsyncProxy.wrap(mailServer, pool);

现在,即使RealMailServer.send()花费一秒钟完成,通过asyncMailServer.send()调用两次也asyncMailServer.send()花费时间,因为这两个调用都是在后台异步运行的。

损坏的

一些开发人员不了解默认InvocationHandler实现的潜在问题。 引用官方文件 :

如上所述,将对代理实例上java.lang.Object声明的hashCodeequalstoString方法的调用进行编码,并将其分派到调用处理程序的invoke方法,就像对接口方法的调用进行编码和分派一样,如上所述。

在我们的案例中,这意味着toString()MailServer其他方法在同一线程池中执行,这非常令人惊讶。 现在,假设您有一个本地代理,其中每个方法调用都会触发远程调用。 通过网络调度equals()hashCode()toString()绝对不是我们想要的。

Guava的AbstractInvocationHandler是一个简单的抽象类,可以正确处理上述问题。 默认情况下,它将equals()hashCode()toString()调度到Object类,而不是将其传递给调用处理程序。 从直接的InvocationHandler重构为AbstractInvocationHandler非常简单:

import com.google.common.reflect.AbstractInvocationHandler;class AsyncHandler<T> extends AbstractInvocationHandler {//...@Overrideprotected Object handleInvocation(Object proxy, final Method method, final Object[] args) throws Throwable {//...}@Overridepublic String toString() {return "Proxy of " + underlying;}
}

而已! 我决定重写toString()来帮助调试。 equals()hashCode()都是从Object继承而来的,一开始就很好。 现在,请查看您的代码库并搜索自定义代理。 如果到目前为止您尚未使用AbstractInvocationHandler或类似的程序,则可能会引入一些细微的错误。

参考: Java和社区博客上的JCG合作伙伴 Tomasz Nurkiewicz 用Guava的AbstractInvocationHandler正确完成了代理 。

翻译自: https://www.javacodegeeks.com/2013/12/proxies-done-right-with-guavas-abstractinvocationhandler.html

guava的正确引入方式

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

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

相关文章

vba执行linux命令,如何使用vba的shell()运行参数的.exe?

我有一个目标文件路径的结构如下例所示。C:\Program Files\Test\foobar.exe /G我需要做的就是使用vba的shell()命令来执行这个文件。如何格式化文件路径以告诉Shell()有一个参数&#xff0c;它需要调用与运行.exe我已经阅读/尝试(无效)在下面的结果在右边。file ""&…

【渝粤题库】陕西师范大学200271 微分几何 作业(专升本)

《微分几何》作业 一. 填空题 曲面的第一基本形式为&#xff08; &#xff09;。空间曲线的基本公式是&#xff08; &#xff09;。曲面在任一点&#xff08;u&#xff0c;v&#xff09;的单位法向量公式为&#xff08; &#xff09;空间曲线的切向量为&#xff08; &#xff…

【渝粤题库】陕西师范大学200771 可视化程序设计

《可视化程序设计》作业 一、单项选择题 1、VB应用程序在&#xff08; &#xff09;模式下不能编辑代码和设计界面。 A 运行B 中断C 设计D 以上均不能 2、将列表框&#xff08;List Box&#xff09;上要显示的内容放到列表框控件上的方法是&#xff08; &#xff09;。 A Addit…

使用Spring Boot和Vue.js构建一个简单的CRUD应用

“我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕&#xff1f; 尝试使用Okta API进行托管身份验证&#xff0c;授权和多因素身份验证。 在本教程中&#xff0c;您将使用Vue.js作为客户端并将Spring Boot作为资源服务器来构…

linux 装windows软件,常用软件的安装(windows/linux)

JavaScript单线程和浏览器事件循环简述JavaScript单线程 在上篇博客的开篇中,我们曾简述了JavaScript的单线程机制和浏览器的事件模型.应很多网友的回复,在这篇文章中将继续展 ...Free Slideshow&comma; Gallery And Lightboxes Scriptshttp://bootstraphelpers.codeplex.c…

【渝粤题库】陕西师范大学201401 环境资源法作业

《环境法》作业 一、单项选择题 1&#xff0e;属于环境法保护客体的有&#xff08; &#xff09; A山林中的大熊猫 B马戏团的金丝猴 C 动物园的老虎 D家养的小狗 2&#xff0e;按环境的形成分将人类环境可划分为&#xff08; &#xff09; A 原生环境和次生环境 B 生存环境和生…

linux安装 icc编译器,安装 Intel Compiler (ifort icc icpc)

在下载目录下解压heqinheqin-dell:~/Downloads$ tar zxvf parallel_studio_xe_2017_update7.tgz进入解压后的文件夹heqinheqin-dell:~/Downloads$ cd parallel_studio_xe_2017_update7/为了记录过程而不用截图&#xff0c;我选择用命令行安装&#xff0c;当然你也可以用install…

【渝粤题库】陕西师范大学201981教育统计与测量 作业 (专升本、高起本)

教育统计与测量[数学]作业 填空 标准分数有____________、两种基本形式。 常见的集中量数有、、。 回归分析中&#xff0c;平方和分解公式为_________。 衡量测验的质量指标有_______、、、。 常用的随机抽样方法有_、、________。 用来衡量一组数据__________的量称为差异量数…

【渝粤题库】陕西师范大学202321投资银行学 作业(专升本)

《投资银行学》作业 一 单项或多项选择题 &#xff08;一&#xff09;多项选择&#xff1a;1&#xff0e;狭义的投资银行一般仅指传统意义上的投资银行&#xff0c;主要指从事证券发行承销和( )的金融机构 A.证券投资 B.证券兑换 C.证券交易 D.证券管理 2&#xff0e;1999年美…

linux 修改docker配置文件,dockerfile动态修改服务配置文件(示例代码)

主要是利用命令envsubst能实现变量的替换并生成新得配置文件以及docker命令行的变量输入等。本次实验主要是编写flume镜像&#xff0c;并在容器启动(docker run)时动态修改配置文件并启动&#xff0c;并向flume发数据&#xff0c;然后发给kafka。此实验的基础&#xff1a;会doc…

【渝粤题库】陕西师范大学209011商业银行信贷管理Ⅱ 作业(专升本)

《商业银行信贷管理Ⅱ》作业 一、单项选择题 1、我国改革开放以来信贷资金来源的最主要支柱是&#xff08; &#xff09;。 A&#xff0e;企业存款 B&#xff0e;财政存款 C&#xff0e;储蓄存款 D&#xff0e;外汇存款 2、汇票的承兑人明确表示按照票据说明的事项&#xff0c;…

cargo maven_与Maven 3,Failsafe和Cargo插件的集成测试

cargo maven开箱即用&#xff0c;可以在Maven中进行单元测试。 因此&#xff0c;它也经常用于集成测试。 这样做的主要缺点是集成测试可能需要花费更多的时间来执行&#xff0c;并且因为没有人喜欢每次构建都要等待很长时间–只是使用-Dmaven.test.skiptrue标志跳过了测试 为了…

【渝粤题库】陕西师范大学210019 学前教育科研方法 作业(专升本)

《学前教育科学研究方法》考评作业 一、单项选择题 1、科学研究是探讨未知的过程&#xff0c;这是科学研究的 特点。 A 客观性 B 创造性 C 继承性 D 控制性 2、在比较长的时间内&#xff0c;对一个儿童或一些儿童的心理发展&#xff0c;或教育规律进行有系统的定期研究是 A纵向…

linux 安装mongodb 64,在CentOS 6.x 64bit上安装MongoDB 3.2社区版

基本安装步骤参考: https://docs.mongodb.org/manual/tutorial/install-mongodb-on-red-hat/1) 创建repo源文件:sudo vim /etc/yum.repos.d/mongodb-org-3.2.repo内容如下:[mongodb-org-3.2]nameMongoDB Repositorybaseurlhttps://repo.mongodb.org/yum/redhat/$releasever/mon…

【渝粤题库】陕西师范大学292241金融市场学Ⅰ 作业(高起专)

《金融市场学Ⅰ》作业 一、单项选择题 1&#xff0e;全国的银行监管权集中在中央&#xff0c;地方没有独立的权力&#xff0c;在中央一级有两家或两家以上结构共同负责的监管模式称之为( )。 A.单元多头金融监管体制     B.集中单一金融监管体制 C.跨国金融监管体制     …

[免费网络研讨会] Java 11的第一印象

一年多以前&#xff0c;我们正焦急地等待新的模块化Java 9的到来。大约在同一时间&#xff0c;引入了一个新的发布周期&#xff0c;该周期将每6个月发布一次新版本&#xff0c;并提供长期支持&#xff08;LTS&#xff09;。每3年发行一次&#xff08;或每6个版本发行一次&#…

linux redhat 命令大全,redhat Linux命令大全

一.启动,关机,登入,登出相关命令登录登出登出停止系统停止系统重启动切断电源把内存里的内容写入磁盘安装lilo启动管理程序安装lilo启动管理程序二. Shell相关命令切换Shell显示命令履历设置命令别名取消命令别名显示命令所在位置查询命令种类显示字符串或者变量内容设置/显示S…

【渝粤题库】陕西师范大学400005 中国传统文化 作业(专升本)

《中国文化传统》作业 一、填空题 1&#xff0e;原始宗教崇拜包括 、 、 、 、 。 2&#xff0e;在儒家经典文献系统中&#xff0c;六经指的是 、 、 、 、 、 . 3&#xff0e;宋代理学家朱熹曾编订《四书》&#xff0c;指的是 、 、 、 。 4&#xff0e;《老子》一书又称 &…

linux rcu机制,Linux RCU机制详解 (透彻)

一:前言RCU机制出现的比较早,只是在linux kernel中一直到2.5版本的时候才被采用.关于RCU机制,这里就不做过多的介绍了,网上有很多有关RCU介绍和使用的文档.请自行查阅.本文主要是从linux kernel源代码的角度.来分析RCU的实现.在讨论RCU的实现之前.有必要重申以下几点:1:RCU使用…

【渝粤题库】陕西师范大学600007 化工基础 作业(专升本)

陕西师范大学 内 部 题 库 教育 &#xff08;yuyueshool&#xff09; 编制 《化工基础》作业 一 填空 1&#xff0e;化工产品种类繁多&#xff0c;生产工艺流程千差万别&#xff0c;具体内容是动量传递、质量传递、热量传递和 &#xff0c;但其基础理论可概括为 和三传一反。…