Java的动态代理常用来包装原始方法调用,用于增强或改写现有方法的逻辑,它在Java技术领域被广为使用,在阿里的Sofa RPC框架序列化中你能看到它的身影,Hibernate的实体类功能增强也是以动态代理的方式解决的,还有Spring吹牛逼的AOP功能也是它搞定的。接下来我们看一个例子,该例子用于对原有的方法调用前后各打印一句话,这也算是对原有类方法的一种增强。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;interface IHello {void say(String s);}// 待加强的目标类
class RealHello implements IHello {@Overridepublic void say(String s) {System.out.println("hello " + s);}}// 增强器
class HelloDelegate implements InvocationHandler {private IHello target;  // 原始对象public HelloProxy(IHello target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("before print");method.invoke(target, args);  // 调用原始对象的方法System.out.println("after print");return null;}}public class DynamicProxy {public static void main(String[] args) {IHello hello = enhanceHello(new RealHello());  # 增强原始方法hello.say("world");}public static IHello enhanceHello(IHello target) {return (IHello) Proxy.newProxyInstance(DynamicProxy.class.getClassLoader(), new Class<?>[] { IHello.class },new HelloDelegate(target));}}
复制代码

输出

before print
hello world
after print
复制代码

为了便于理解,我们用图来表示上面的对象的关系。我们调用Proxy.newProxyInstance产生了一个匿名类实例,该实例同样实现了IHello接口,它的作用就是用来替代原生的RealHello实例。这个匿名实例持有HelloDelegate实例的引用,当你对这个匿名实例进行方法调用时,它会将调用逻辑委托给HelloDelegate实例的invoke方法。HelloDelegate实例内部又持有原生RealHello对象的引用,所以用户就可以在invoke方法里实现任意附加逻辑,以及对原生RealHello对象的调用。

上面是jdk自带的动态代理技术,它的缺点是必须定义接口才能实现目标对象的方法增强,甚至想使用abstract class来替代也不行。所以开源市场上冒出了好几个动态代理的库,用于替代原生的jdk动态代理技术,它们不仅仅功能更强大,而且内部使用了字节码增强实现,在性能上还也要比原生jdk高出很多。

javaassist

javaassist是使用最广泛的动态代理开源库。下面我们使用javaassist实现一个无需定义接口就能增强原始方法的例子。

import java.lang.reflect.Method;import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyFactory;class RealHello {public void say(String s) {System.out.println("hello " + s);}}class HelloDelegate<T> implements MethodHandler {private T target;public HelloDelegate(T target) {this.target = target;}@Overridepublic Object invoke(Object self, Method method, Method proceed, Object[] args) throws Throwable {System.out.println("before print");method.invoke(target, args);System.out.println("after print");return null;}}public class DynamicProxy {public static void main(String[] args) {RealHello hello = enhanceHello(new RealHello());hello.say("world");}@SuppressWarnings("unchecked")public static <T> T enhanceHello(T target) {ProxyFactory proxy = new ProxyFactory();proxy.setSuperclass(RealHello.class);try {HelloDelegate<T> delegate = new HelloDelegate<T>(target);// create方法传递了两个空数组// 分别代表构造器的参数类型数组和构造器的参数实例数组return (T) proxy.create(new Class<?>[0], new Object[0], delegate);} catch (Exception e) {e.printStackTrace();}return null;}}
复制代码

输出

before print
hello world
after print
复制代码

看起来和原生jdk提供的动态代理区别并不大,达到的效果是一样的。只不过这里要简单了很多,省去了接口类的定义。javaassist的ProxyFactory还提供了方法过滤器,它可以选择性地对特定方法进行增强。

Python

Python是动态语言,对于上面复杂的动态代理技术,它一笑而过。

下面我们来看看Python如果实现所谓的动态代理功能

class Proxy(object):def __init__(self, target):self.target = targetdef __getattribute__(self, name):target = object.__getattribute__(self, "target")attr = object.__getattribute__(target, name)def newAttr(*args, **kwargs):  # 包装print "before print"res = attr(*args, **kwargs)print "after print"return resreturn newAttrclass RealHello(object):def prints(self, s):print 'hello', sif __name__ == '__main__':t = RealHello()p = Proxy(t)p.prints("world")
复制代码

输出

before print
hello world
after print
复制代码

我们使用了神奇的__getattribute__方法。在Python里面类的属性(方法)都是一个对象,我们先拿到这个类方法对象attr,然后对这个类方法对象进行包装,再返回包装后的新方法对象newAttr。 注意在获取target对象时,不能直接使用self.target,因为self.target会再次调用__getattribute__方法,这样就会导致死循环致堆栈过深曝出异常。取而代之应该使用object.__getattribute__方法来获取对象的属性值。

以上就是Python实现动态代理的方案,读者们,你们是否觉得Python更加简单呢?欢迎大家一起来评论区吵架。

精彩文章,关注公众号「码洞」

看完Java的动态代理技术——Pythoner笑了相关推荐

  1. Java动态代理技术-我的浅显认识

    说到代理,大家不由想到23种设计模式中的代理模式.JDK的动态代理技术正是基于代理模式,并且核心使用了反射机制实现的.首先,便于理解,我们看看demo级别的代理模式(也就对应地叫做静态代理): int ...

  2. 深入理解Java反射+动态代理,java开发面试笔试题

    我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家. 扫描二维码加VX好友,拉你进[程序员面试学习交流群]免费领取.也欢迎各位一起在群里探讨技术. 答: ...

  3. [Java|面试] 面试被问Java的动态代理机制,能说说吗

    Java的动态代理机制 文章目录 Java的动态代理机制 0. 什么是代理 1.动态代理和静态代理的区别 2. 使用代理的情况 3. 动态代理的构成 4. JDK中的动态代理 5. 手写一个JDK动态 ...

  4. 代理模式及Java实现动态代理

    代理模式 定义:给某个对象提供一个代理对象,并由代理对象控制对于原对象的访问,即客户不直接操控原对象,而是通过代理对象间接地操控原对象. 代理模式UML图 在上图中: RealSubject 是原对象 ...

  5. Java - JDK动态代理原理

    Java - JDK动态代理原理 前言 一. JDK动态代理源码分析 1.1 生成目标代理类 getProxyClass0 1.1.1 KeyFactory 生成接口的虚引用 1.1.2 ProxyC ...

  6. 设计模式总结——代理模式以及java的动态代理

    定义 给目标对象一个代理对象,并由代理对象控制对目标对象的引用.联想到生活中就像是海外代购 既然是代理,就说明他要做的事情要比你直接去做要做的多,这就联系到了方法的增强,也就联系到了AOP,面向切面. ...

  7. java的动态代理机制详解

    2019独角兽企业重金招聘Python工程师标准>>> 参考资料 1.java的动态代理机制详解 转载于:https://my.oschina.net/Howard2016/blog ...

  8. Spring-AOP动态代理技术(底层代码)

    1.JDK代理:基于接口的动态代理技术 目标对象必须有接口,目标对象有什么方法,目标接口就有什么方法, 运行期间基于接口动态生成代理对象,所以代理对象也就有目标对象同样的方法. 注意:以下代码只是底层 ...

  9. spring—AOP 的动态代理技术

    AOP 的动态代理技术 常用的动态代理技术 JDK 代理 : 基于接口的动态代理技术 cglib 代理:基于父类的动态代理技术 JDK 代理 public class proxy {@Testpubl ...

最新文章

  1. 服务发现框架选型,Consul还是Zookeeper还是etcd
  2. GitLab 添加组员到指定小组
  3. axios_的请求响应结果的结构---axios工作笔记006
  4. freeMarker fmpp 解析PowerDesign PDM探索
  5. httpclient4.x 中文版帮助文档,最新官方版翻译版(第一章 下)
  6. Redis 命令 - 在线参考
  7. 计算机 管理 用户,一种计算机系统及管理计算机用户权限的方法_2
  8. 仿微信在线聊天源码 DuckChat聊天系统PHP采用 PHP 编写的聊天软件,简直就是一个完整的迷你版微信
  9. 蓝桥杯 受伤的皇后(dfs)
  10. MySQL第一节课总结
  11. filter java exclude_Filter中排除对指定URL的过滤
  12. The server time zone value .. is unrecognized or represents more than one time zone
  13. normal模式/loader模式/MASKROM模式
  14. SpringCloud(H版alibaba)之基本框架篇
  15. android app 仿小米全面屏手势返回UI样式
  16. Android 的 LiveReload — jimu Mirror
  17. mysql日志 事务问题_mysql因为事务日志问题无法启动
  18. 2021年在全球及中国卫星发射数量、在轨卫星及市场规模分析[图]
  19. 多媒体技术(大计基复习资料)
  20. 找回wps未保存文件

热门文章

  1. Arrays对数组,二分查找,冒泡排序
  2. Windows下Spring3.x计划任务实现定时备份MySql数据库
  3. mysql_real_escape_string 报错_addslashes与mysql_real_escape_string的区别
  4. 借助桶排序思想完成的一道题
  5. 算法(10)-leetcode-explore-learn-数据结构-链表双指针技巧
  6. 大数据学习(06)-- 云数据库
  7. java 场景处理,将黄瓜场景示例作为一个场景处理
  8. php 单选框选中事件,html中的checkbox和radio事件选择用法详解
  9. SpringNBoot日志配置
  10. 王道考研 计算机网络11 数据链路层 封装成帧 透明传输 流量控制 停止-等待协议 后退N帧协议GBN 选择重传协议SR