当前位置:首页 > CN2资讯 > 正文内容

Java 深入学习(28) —— 静态代理与动态代理java静态动态

2天前CN2资讯


代理是基本的设计模式之一,它是为了提供额外的或不同的操作,而插入的用来代替“实际”对象的对象。这些操作通常涉及与“实际”对象的通信,因此代理通常充当中间人的角色。


1 静态代理


代理这种设计模式其实很好理解,基本就是最简单的一个“组合”。

比如说下面这个例子,我们有 RealObject 这个类,本来可以直接调用 RealObject 类的 doSomething() 和 somethingElse()方法。

代理模式就非要把RealObject 类当成 SimpleProxy类的一个成员字段放在 SimpleProxy 类里面。然后因为RealObject类和 SimpleProxy类都实现了Interface这个接口,所以SimpleProxy类里也有doSomething()和somethingElse()方法。而且 SimpleProxy 类里的 doSomething() 和somethingElse()方法就是傻瓜式的调用 RealObject类的doSomething()和 somethingElse() 方法。

package com.test.class_obj; interface Interface { void doSomething(); void somethingElse(String arg); } class RealObject implements Interface { public void doSomething() { System.out.println("doSomething"); } public void somethingElse(String arg) { System.out.println("somethingElse " + arg); } } class SimpleProxy implements Interface { private Interface proxied; public SimpleProxy(Interface proxied) { this.proxied = proxied; } public void doSomething() { System.out.println("SimpleProxy doSomething"); proxied.doSomething(); } public void somethingElse(String arg) { System.out.println("SimpleProxy somethingElse " + arg); proxied.somethingElse(arg); } } public class SimpleProxyDemo { public static void consumer(Interface iface) { iface.doSomething(); iface.somethingElse("bonobo"); } public static void main(String[] args) { consumer(new RealObject()); System.out.println("-----------------------"); consumer(new SimpleProxy(new RealObject())); } }

SimpleProxy 被插入到了“客户端”与 RealObject 之间,因此它会执行操作,然后调用 RealObject 上相同的方法。

在任何时刻,只要想将额外的操作从“实际”对象中分离到不同的地方,特别是希望能够很容易的做出修改,从 没有使用额外操作 转为 使用额外操作,或者反过来,代理就显得很有用(设计模式的关键就是封装修改)。

例如:如果想要跟踪对 RealObject 中的方法的调用,或者想要度量这些调用的开销,这些额外的操作时,因为这些额外操作而添加的代码不能合并到 RealObject 的代码中,使用代理便可以很容易的添加或移除它们。

代理类里能非常好地控制,辅助被代理类,甚至是增加额外的功能。而且一般来说代理类B和被代理A都会实现同样的接口,这样对用户端(就是上面例子里的Consumer类)的代码没有任何影响,耦合很低。


2 动态代理

Java 的动态代理可以动态地创建代理动态地处理对所代理方法的调用

package com.test.class_obj; import java.lang.reflect.*; class DynamicProxyHandler implements InvocationHandler { private Object proxied; public DynamicProxyHandler(Object proxied) { this.proxied = proxied; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("**** proxy: " + proxy.getClass() + ", method: " + method + ", args: " + args); if (args != null) for (Object arg : args) System.out.println(" " + arg); return method.invoke(proxied, args); } } class SimpleDynamicProxy { public static void consumer(Interface iface) { iface.doSomething(); iface.somethingElse("bonobo"); System.out.println("----------------------"); } public static void main(String[] args) { RealObject real = new RealObject(); consumer(real); // 创建动态代理 Interface proxy = (Interface) Proxy.newProxyInstance( // 类加载器(可以从已经被加载的对象中获取其类加载器) Interface.class.getClassLoader(), // 希望代理实现的接口列表 new Class[]{Interface.class}, // InvocationHandler 接口的一个实现 new DynamicProxyHandler(real)); consumer(proxy); } }doSomething somethingElse bonobo ---------------------- **** proxy: class com.test.class_obj.$Proxy0, method: public abstract void com.test.class_obj.Interface.doSomething(), args: null doSomething **** proxy: class com.test.class_obj.$Proxy0, method: public abstract void com.test.class_obj.Interface.somethingElse(java.lang.String), args: [Ljava.lang.Object;@4b67cf4d bonobo somethingElse bonobo ---------------------- Process finished with exit code 0

动态代理可以将所有调用重定向到调用处理器(DynamicProxyHandler)。因此通常会向调用处理器的构造器传递一个“实际”对象的引用(real),从而使得调用处理器在执行其中介任务(iface.doSomething();)时,可以将请求转发(invoke())。

invoke()方法中传递进来了代理对象(Object proxy),以防需要区分请求的来源。

在 invoke()内部,在代理上调用方法时需要格外当心,因为对接口的调用将被重定向为对代理的调用。

Method.invoke() 将请求转发给被代理的对象,并传入必要的参数。


newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
  • 第一个ClassLoader是为了生成B类的Class对象。作用是根据一组类的字节码byte[]直接生成这个类的Class对象。

  • 第二个参数是由委托类实现的接口的Class对象数组。主要是包含了最重要的代理类需要实现的接口方法的信息。

  • 最后一个最重要的就是一个实现了 InvocationHandler接口 的对象。InvocationHandler接口在java.lang.reflect包里。最主要的就是定义了invoke( )方法。它就是假设在已经动态生成了最后的proxy代理对象,以及所有接口定义的方法Method对象以及方法的参数的情况下,定义我们要怎么调用这些方法的地方。

3 通过传递参数,过滤方法调用

package com.test.class_obj; import java.lang.reflect.*; class MethodSelector implements InvocationHandler { private Object proxied; public MethodSelector(Object proxied) { this.proxied = proxied; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 通过方法名来过滤方法的调用 if (method.getName().equals("interesting")) { System.out.println("----通过传入的参数来过滤方法的调用----"); System.out.println("Proxy detected the interesting method"); System.out.println("----------------------------------"); } return method.invoke(proxied, args); } } interface SomeMethods { void boring1(); void boring2(); void interesting(String arg); void boring3(); } class Implementation implements SomeMethods { public void boring1() { System.out.println("boring1"); } public void boring2() { System.out.println("boring2"); } public void interesting(String arg) { System.out.println("interesting " + arg); } public void boring3() { System.out.println("boring3"); } } class SelectingMethods { public static void main(String[] args) { SomeMethods proxy = (SomeMethods) Proxy.newProxyInstance( SomeMethods.class.getClassLoader(), new Class[]{SomeMethods.class}, new MethodSelector(new Implementation())); proxy.boring1(); proxy.boring2(); proxy.interesting("bonobo"); proxy.boring3(); } }

这里我们只是查看了方法名,其实还可以查看方法签名的其他方面,甚至可以搜索特定的参数值。

4 参考资料

1、《Java编程思想》

2、Java 动态代理作用是什么?
https://www.zhihu.com/question/20794107

3、Java JDK动态代理Proxy类的原理是什么?
https://www.zhihu.com/question/49337471?rf=49332059


    你可能想看:

    扫描二维码推送至手机访问。

    版权声明:本文由皇冠云发布,如需转载请注明出处。

    本文链接:https://www.idchg.com/info/24782.html

    分享给朋友:

    “Java 深入学习(28) —— 静态代理与动态代理java静态动态” 的相关文章

    高防IP的重要性及其在网络安全中的应用

    理解高防IP对维护网络安全的重要性是当今每个企业都应该重视的事。高防IP,它的全名是高防御IP地址,主要是为抵御各种网络攻击而特别设计的。随着网络攻击手段的日趋复杂化,很多公司和个人的在线安全面临着巨大的威胁。在这种背景下,高防IP凭借其流量清洗和分流等技术手段,为企业提供了一道坚实的安全屏障。 高...

    DMIT VPS评测:高性能与稳定性的完美结合

    在了解DMIT VPS之前,我想先分享一下我对这家公司的最初印象。记得第一次听到DMIT时,它的名字总是在VPS领域中流传。人们提到它时,无一不带着敬仰,增加了我对它的好奇心。自从它在2017年成立以来,DMIT便以其优秀的服务和产品迅速吸引了不少用户。我也开始关注起它背后的故事。 DMIT的崛起显...

    搬瓦工:性能卓越的VPS服务平台,为您的项目提供最佳选择

    搬瓦工概述 在网上冲浪的时候,大家可能都听说过“搬瓦工”,但对于它的真正含义了解的并不多。搬瓦工(BandwagonHost)是一家以提供虚拟私人服务器(VPS)而闻名的公司,采用KVM架构,深受用户青睐。我在使用搬瓦工的过程中发现,选择这个平台的用户不仅因为它的价格相对较低,还因为它提供的服务非常...

    AMD EPYC 7K62:数据中心理想选择的高性能服务器CPU

    在数据中心的世界中,选对一款合适的服务器CPU至关重要。今天,我想聊聊AMD EPYC 7K62,这款处理器以其高性价比赢得了许多用户的青睐。这个型号的CPU被设计为服务器专用,接下来我们将深入了解它的基本信息、技术规格以及市场定位。 AMD EPYC 7K62的型号很直接,名称中就带有AMD和EP...

    搬瓦工官网是哪个?全面解析搬瓦工的官方链接和服务

    搬瓦工官网是哪个? 当我提到“搬瓦工”,很多朋友可能会想知道它的官网到底在哪儿。其实,搬瓦工的主官网地址是 bandwagonhost.com。不过,有时访问这个主域名可能会遇到点小问题。为了方便用户,搬瓦工还提供了几个官方镜像站,包括 bwh1.net、bwh8.net、bwh81.net、bwh...

    Vultr注册送50美元优惠活动详细指南

    Vultr新用户注册活动概述 在寻找合适的云服务提供商时,我总是觉得选对平台会显得尤为重要。Vultr做为一个非常受欢迎的云服务提供商,给新用户带来了一项非常吸引人的优惠活动——注册即送50美元。这个活动让我感到非常兴奋,也让更多人有机会体验到高性价比的VPS服务。 这项活动非常简单易行。新用户只需...