千家信息网

Java8动态代理的技巧是什么

发表于:2025-02-23 作者:千家信息网编辑
千家信息网最后更新 2025年02月23日,本篇内容介绍了"Java8动态代理的技巧是什么"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!动态代理
千家信息网最后更新 2025年02月23日Java8动态代理的技巧是什么

本篇内容介绍了"Java8动态代理的技巧是什么"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

动态代理(Dynamic proxies)是 Java 1.3 引入的特性,在 J2EE 的远程调用中应用非常广泛。给定一个抽象接口以及这个接口的具体实现,就可以通过创建两个额外的类来实现这个接口的远程调用了(如,跨JVM)。首先,在 源JVM上实现相应的接口,并将调用细节序列化后通过网络传输。然后,在目标JVM上,获取到序列化后的调用的细节,并分配给具体的的类去调用。

没有动态代理和反射,开发者不得不为每个远程接口提供两个类。一个动态代理是运行时产生的类,实现一个或多个接口,接口中每个方法的调用都会自动转换为 java.runtime.InvocationHandler 提供的方法调用:

public interface InvocationHandler {     Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }

InvocationHandler决定如何处理调用,如何在运行时使用方法的有效信息,包括注解、参数类型及方法的返回类型。这样就可以实现一个 通用逻辑来定义方法调用的分发。一旦你写好了一个InvocationHandler,就可以调用代理类的 handler 来完成所有接口中的方法,而不是为每一个接口写一个单独的实现。

远程调用最近几年里已经没那么受欢迎了,因为开发者需要明白方法调用分发与网络请求发送在语义和失败模式上的本质区别,但是动态代理仍保留在语言当 中。在这篇文章中,我将讨论动态代理其他方面的作用。在下一篇文章中,将讨论动态代理新的实现技术,这些技术是由于 Java 8 引入 lambda 表达式和默认方法而产生的。

魔法匹配器

这些年来,我一直在使用一个"Magic" 对象,以便能够写出简洁的流式测试。我定义了一个"magic"的接口,然后通过一个动态代理来实现目标行为。比较特别的是,在测试时候用"magic builders"来生成测试值,然后用"magic matchers"来表述断言属性测试的结果。我们这里只关注匹配器。

我们有一个Person支撑类,这是一个典型的bean——成员变量是私有的,通过getter和setter方法暴露。

public class Person {      private String name;     private int age;      // insert getters and setters here }

使用一个简单Hamcrest类,我们有两种方式来断言该类的实例。一种方法是单独抽取每个值,分开断言。

assertThat(person.getName(), containsString("Smith")); assertThat(person.getAge(), greaterThan(30));

另一种方式是使用allOf和hasProperty方法,将对象作为一个整体,通过一组期望值来匹配。

assertThat(person, allOf(     hasProperty("name", containsString("Smith")),     hasProperty("age", greaterThan(30)));

这样能很好的工作,但是这种方式对 Hamcrest 描述整体匹配和错误匹配并没有什么帮助。

Expected: (hasProperty("name", a string containing "Putey") and hasProperty("age", a value greater than <43>)) but: hasProperty("age", a value greater than <43>) property 'age' <42> was less than <43>

hasProperty的匹配在类型一致性的检测也是非常弱的:我们可以写成 hasProperty("age", containsString("Smith")),这样类型检测也不会拒绝。

我们真正想要的是一个流式API,能够像下面一样使用:

assertThat(person, aPerson()     .withName("Arthur Putey")     .withAge(greaterThan(43)));

并且能够很好且易于理解地报告错误的匹配:

Expected: name: a string containing "Putey" age: a value greater than <43>     but: age: <42> was less than <43>

很容易写一个上述功能的自定义匹配器,但是不得不很乏味地写很多次。幸运的是,可以通过动态代理来帮我们解决。首先,我们定义一个流式接口,该接口包含如下方法:

interface PersonMatcher extends Matcher {     PersonMatcher withName(String expected);     PersonMatcher withName(Matcher matching);     PersonMatcher withAge(int expected);     PersonMatcher withAge(Matcher matching); }

然后,我们使用在一个名为 MagicMatcher 的类上的静态方法来获取动态代理,该代理实现了这个接口,然后通过方法调用来获取调节表达式:

static PersonMatcher aPerson() {     return MagicMatcher.proxying(PersonMatcher.class); }

每个方法的调用都通过代理类的"interpreted"方法来实现,该代理从方法("withAge")中获取属性("age"),并指定调用匹 配对象上的("getAge")方法来获取属性值。属性的名称以及匹配中对应的值将会被存储,直到代理类的 match 或 describeMismatch 方法被调用(这就是为什么接口需要继承 Matcher)。在调用的时候需要抽取并测试对象的属性,如果有必要,会创建错误匹配报告。

这种方式是轻量级的,我们可以引入任何新的自定义的接口,并在测试中重用,这样,是非常有利于编写自定义Hamcrest匹配器的,因为不再需要编 写接口的实现。所有需要生成的在接口中定义的匹配器行为,都只需要实现一次,我们通过一个合适的 InvocationHandler 来完成逻辑功能的实现。

"Java8动态代理的技巧是什么"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

方法 接口 代理 动态 测试 属性 方式 类型 对象 错误 技巧 两个 内容 功能 可以通过 序列 开发者 技术 报告 整体 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 人工智能网络安全的发展 网络安全法规定 网络安全 市委网信办行业网络安全检查 目前商用的主流数据库数据模型是 网络技术维护的日常工作 杭州文鼎网络技术有限公司 如何将图片添加进数据库中 衢州电子网络技术包括什么 数据库主外键是主键吗 python短信群发软件开发 由文件提供输入数据库 数据库os用户 有效服务器 2008数据库质疑恢复日志 对网络安全提出的问题 数据库判断当天是星期几 济南智能养老软件开发系统 aoi检测设备软件开发语言 java处理俩个数据库 和讯网企业社会责任数据库总得分 路由器设置web服务器 网络安全岗前培训及考核制度 安徽联想服务器维修维保价格 摄像头如何把数据加载到数据库 nas如何设置服务器名称 网络技术最新研究 网络安全界别 网络安全的定义 特征 目标 软件开发java架构新技术 个人服务器域名备案
0