实施动态代理-比较

有时需要拦截某些方法调用,以便每次调用被拦截方法时都执行自己的逻辑。 如果您不属于Java EE的CDI领域,并且不想使用诸如Aspectj之类的AOP框架,那么您将有一个简单而有效的替代方法。

从1.5版开始,JDK附带了类java.lang.reflect.Proxy,该类使您可以为给定的接口创建动态代理。 每次应用程序调用代理上的方法时,都会调用位于动态创建的类后面的InvocationHandler。 因此,您可以在调用某个框架或库的代码之前动态控制执行什么代码。

在JDK的代理实现旁边,像javassist或cglib这样的字节码框架提供了类似的功能。 在这里,您甚至可以对现有的类进行子类化,并确定要转发给超类的实现的方法以及要拦截的方法。 当然,这会带来项目依赖的另一个库的负担,并且可能需要不时更新,而运行时环境中已经包含了JDK的Proxy实现。

因此,让我们仔细看看并尝试这三种选择。 为了将javassist和cglib的代理与JDK实现进行比较,我们需要一个由简单类实现的接口,因为JDK机制仅支持接口,而没有子类:

public interface IExample {void setName(String name);
}public class Example implements IExample {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}
}

为了将代理上的方法调用委托给某个实际对象,我们创建了上面的Example类的实例,并通过最终声明的变量在InvocationHandler中对其进行了调用:

final Example example = new Example();
InvocationHandler invocationHandler = new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {return method.invoke(example, args);}
};
return (IExample) Proxy.newProxyInstance(JavaProxy.class.getClassLoader(), new Class[]{IExample.class}, invocationHandler);

从代码示例中您可以看到,代理的创建非常简单:调用静态方法newProxyInstance()并提供ClassLoader,应由代理实现的接口数组以及InvocationHandler接口的实例。 为了演示起见,我们的实现仅转发我们之前创建的Example实例。 但是,在现实生活中,您当然可以执行更高级的操作,以评估例如方法名称或其参数。

现在我们来看一下使用javassist完成相同操作的方式:

ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(Example.class);
Class aClass = factory.createClass();
final IExample newInstance = (IExample) aClass.newInstance();
MethodHandler methodHandler = new MethodHandler() {@Overridepublic Object invoke(Object self, Method overridden, Method proceed, Object[] args) throws Throwable {return proceed.invoke(newInstance, args);}
};
((ProxyObject)newInstance).setHandler(methodHandler);
return newInstance;

在这里,我们有一个ProxyFactory,它想知道应该为哪个类创建子类。 然后,我们让ProxyFactory创建一个整个类,该类可以根据需要多次重用。 这里的MethodHandler与InvocationHandler相似,后者是为实例的每次方法调用而调用的。 在这里,我们再次将调用转发到之前创建的Example实例。

最后但并非最不重要的一点,让我们看一下cglib的代理:

final Example example = new Example();
IExample exampleProxy = (IExample) Enhancer.create(IExample.class, new MethodInterceptor() {@Overridepublic Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {return method.invoke(example, args);}
});
return exampleProxy;

在cglib世界中,我们有一个Enhancer类,可用于通过MethodInterceptor实例实现给定的接口。 回调方法的实现看起来与javassist示例中的实现非常相似。 我们只是通过反射API将方法调用转发到Example的现有实例。

既然我们已经看到了三种不同的实现,我们还希望评估它们的运行时行为。 因此,我们编写了一个简单的单元测试,它测量了每个实现的执行时间:

@Test
public void testPerformance() {final IExample example = JavaProxy.createExample();long measure = TimeMeasurement.measure(new TimeMeasurement.Execution() {@Overridepublic void execute() {for (long i = 0; i < JavassistProxyTest.NUMBER_OF_ITERATIONS; i++) {example.setName("name");}}});System.out.println("Proxy: "+measure+" ms");
}

我们选择大量的迭代,以便强调JVM并让HotSpot编译器为经常执行的段落创建本机代码。 下表显示了三种实现的平均运行时间:

2014-01-14_proxies_chart

为了完全显示代理实现的影响,该图表还显示了对Example对象(“无代理”)进行标准方法调用的执行时间。 首先,我们可以记录下来,代理实现比方法本身的普通调用慢大约10倍。 但是我们也注意到三种代理解决方案之间的差异。 令人惊讶的是,JDK的Proxy类几乎与cglib实现一样快。 只有javassist的退出时间是cglib的两倍左右。

结论:运行时代理易于使用,您有不同的处理方式。 JDK的代理仅支持接口代理,而javassist和cglib允许您对现有类进行子类化。 代理的运行时行为比标准方法调用慢大约10倍。 三种解决方案在运行时间方面也有所不同。

参考: 实现动态代理–来自我们的JCG合作伙伴 Martin Mois在Martin's Developer World博客上的比较。

翻译自: https://www.javacodegeeks.com/2014/01/implementing-dynamic-proxies-a-comparison.html

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

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

相关文章

结构专业规范大全_1.2万篇 建筑行业规范大全套!速来!

应广大站友以及会员用户对建筑规范的要求&#xff0c;我们整理了近几年来国家发布的各个专业的标准、规范、图集&#xff0c;以及全国各地共32个地区的区域标准&#xff0c;总计12000余篇&#xff0c;共计80G的建筑行业规范&#xff01;BIMer自学站将会在一到两个月的之间内相继…

数据库如何进行索引优化

数据库索引 1&#xff0e;什么是索引 在数据库中&#xff0c;索引的含义与日常意义上的“索引”一词并无多大区别&#xff08;想想小时候查字典&#xff09;&#xff0c;它是用于提高数据库表数据访问速度的数据库对象。A&#xff09;索引可以避免全表扫描。多数查询可以仅扫描…

第二章总结

第二章 寄存器 1.CPU概述 一个典型的CPU由运算器、控制器、寄存器等器件组成。 内部总线实现CPU内部各个器件之间的联系。 外部总线实现CPU和主板上其它器件的联系。 2.通用寄存器 8086CPU中&#xff0c;寄存器AX, BX, CX, DX通常用于存放一般性数据&#xff0c;称为通用寄存器…

ashly理器4.8软件汉化版_AMD 处理器核心比英特尔多还更便宜?英特尔回应

IT之家 9 月 25 日消息 英特尔已在本月初发布了 11 代酷睿移动处理器&#xff0c;搭载 11 代酷睿的产品最早将在 10 月上市。现在&#xff0c;新浪科技访了英特尔公司中国零售销售集团总经理唐炯&#xff0c;就 11 代酷睿产品进行讨论。在谈到 AMD 处理器比英特尔便宜&#xff…

OutOfMemoryError:解决方案反模式

这些年来&#xff0c;我们一直密切关注以OutOfMemoryError消息的不同形式打包的问题。 通过专门的服务&#xff08;例如Google警报&#xff09;&#xff0c;每天就特定关键字的新问题进行摘要&#xff0c;使我们对应用程序因日志中的java.lang.OutOfMemoryError失败而出现的情况…

leetcood学习笔记-58-最后一个单词的长度

题目描述&#xff1a; 第一次解答&#xff1a; class Solution:def lengthOfLastWord(self, s: str) -> int:Ls.strip().split(" ")if L[-1]"" :return 0return len(L[-1]) 优化后&#xff1a; class Solution:def lengthOfLastWord(self, s: str) ->…

Plyr – 简单,灵活的 HTML5 媒体播放器

Plyr 是一个简单的 HTML5 媒体播放器&#xff0c;包含自定义的控制选项和 WebVTT 字幕。它是只支持现代浏览器&#xff0c;轻量&#xff0c;方便和可定制的媒体播放器。还有的标题和屏幕阅读器的全面支持。 在线演示 源码下载 您可能感兴趣的相关文章网站开发中很有用的 …

第一章 SpringBoot快速入门

1.1、包依赖 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.14.RELEASE</version><relativePath/> <!-- lookup parent from repository --> …

solaris配置php,Solaris下安装Oracle_启动Oracle及监听

无论是在Linux下还是在Solaris下都安装过很多次Oracle&#xff0c;几乎都没成功过。最开始安装的时候连安装页面都见不到&#xff0c;后来&#xff0c;能够看到安无论是在Linux下还是在Solaris下都安装过很多次Oracle&#xff0c;几乎都没成功过。最开始安装的时候连安装页面都…

【C++】满二叉树问题

/* 给出一棵满二叉树的先序遍历&#xff0c;有两种节点&#xff1a;字母节点&#xff08;A-Z&#xff0c;无重复&#xff09;和空节点&#xff08;#&#xff09;。要求这个树的中序遍历。输出中序遍历时不需要输出#。 满二叉树的层数n满足1<n<5。Sample Input: ABC#D#ESa…

NativeScript - JS 构建跨平台的原生 APP

使用 NativeScript&#xff0c;你可以用现有的 JavaScript 和 CSS 技术来编写 iOS、Android 和 Windows Phone 原生移动应用程序。由原生平台的呈现引擎呈现界面而不是 WebView&#xff0c;正因为如此&#xff0c;应用程序的整个使用体验都是原生的。 NativeScript 使您可以使用…

java乱码base64,解决 JAVA WebSocket 解析 base64 后中文字符串乱码

解决 JAVA WebSocket 解析 base64 后中文字符串乱码解决 JAVA WebSocket 解析 base64 后中文字符串乱码春风如贵客&#xff0c;一到便繁华。各位看官先赞再看&#xff0c;养成好习惯(●?&#xff40;●)前言&#xff1a;项目基于WebSocket实现了一个功能&#xff0c;其中要接受…

Riot - 比 Facebook React 更轻量的 UI 库

Riot 是一个类似 Facebook React 的用户界面库&#xff0c;只有3.5KB&#xff0c;非常轻量。支持IE8 浏览器的自定义标签&#xff0c;虚拟 DOM&#xff0c;语法简洁。Riot 给前端开发人员提供了除 React 和 Ploymer 之外的新选择&#xff0c;值得一试。 在线演示 源码下载…

FormatJS – 让你的 Web 应用程序国际化

FormatJS 是一个模块化的集合&#xff0c;保护各种 JavaScript 国际化库&#xff0c;例如格式化数字&#xff0c;日期和字符串。它包括一组建立在 JavaScript 的国际内置插件和全行业的国际化标准&#xff0c;再加上一套集成的通用模板和组件库。 在线演示 源码下载 您可能…

Javascript执行上下文和执行栈

什么是执行上下文&#xff1f; 执行上下文就是当前JavaScript代码被解析和执行时所在环境的抽象概念&#xff0c;JavaScript中运行任何的代码都是在执行上下文。 什么是执行栈&#xff1f; 执行栈&#xff0c;在其他编程语言中也被叫做调用栈&#xff0c;具有LIFO&#xff08;后…

基于swagger进行接口文档的编写

0. 前言 近期忙于和各个银行的代收接口联调&#xff0c;根据遇到的问题&#xff0c;对之前编写的接口进行了修改&#xff0c;需求收集和设计接口时想到了方方面面&#xff0c;生产环境下还是会遇到意想不到的问题&#xff0c;好在基本的执行逻辑已确定&#xff0c;因此只是对接…

Hyhyhy – 专业的 HTML5 演示文稿工具

Hyhyhy 是创建好看的 HTML5 演示文档的工具。它具备很多的特点&#xff1a;支持 Markdown&#xff0c;嵌套幻灯片&#xff0c;数学排版&#xff0c;兼容性&#xff0c;语法高亮&#xff0c;使用 Javascript API &#xff0c;方便的骨架。它支持 Firefox 2 , Safari 3 , Opera 9…

Java开发知识之Java的枚举

Java开发知识之Java的枚举 一丶什么是枚举 枚举可以理解为就是常量,在Java中我们定义常量.都是用 final语句. C中都是用const关键字. 枚举跟C概念都是一样的.就是特定的常量而已. 二丶Java中的枚举 java中的常量.一般都是final定义.但是我们讲过.final定义的常量.初始化的时候可…

linux php7 mongodb,CentOS 7下安装配置PHP7跟LAMP及MongoDB和Redis

CentOS 7下安装配置PHP7跟LAMP及MongoDB和Redis我是想能yum就yum&#xff0c;所有软件的版本一直会升级&#xff0c;注意自己当时的版本是不是已经更新了。首先装CentOS 7装好centos7后默认是不能上网的cd /etc/sysconfig/network-scripts/找到形如ifcfg-enp0s3的文件&#xff…

基于 Bootstrap 的响应式后台管理面板

你想建立一个后台管理面板或者分析仪表板吗&#xff1f;不需从头开始&#xff0c;Keen IO Bootstrap 是一个响应式的仪表盘模板&#xff0c;可以帮助你在几分钟内呈现数据&#xff0c;让你可以创建一个有吸引力的&#xff0c;定制的分析仪表板&#xff0c;随时可以展现给你的团…