[Java] 代理模式 Proxy Mode

文章目录

  • [Java] 代理模式 Proxy Mode
    • 1. 代理思想
    • 2.java.lang.reflect.Proxy类
      • 2.1 利用反射创建proxy类
        • 2.1.1 动态代理实现一
        • 2.1.2 动态代理实现二
        • 2.1.3 动态代理实现三

1. 代理思想

场景: 假设我们有一个interface Calculator, Class CalculatorImpl和Proxy CalculatorProxy为接口的实现类,Class CalculatorImpl为目标类,是我们需要实现的业务逻辑,Proxy CalculatorProxy为代理类。 实例化Proxy CalculatorProxy时,可以将Class B的实例传入,通过该实例可以调用目标类的目标方法。

举例:

public interface Calculator {int add(int i, int j);
}
public class CalculatorImpl implements Calculator {@Overridepublic int add(int i, int j) {return i + j;}
}
public class CalculatorProxy implements Calculator {private Calculator target;public CalculatorProxy (Calculator target){this.target=target;}@Overridepublic int add(int i, int j) {System.out.println("preCalculator\n");//目标方法int result = target.add(i, j);System.out.println("postCalculator\n");return result;}
}

主程序调用时:

public class mainTest {public static void main(String[] avrg){//目标类实例化CalculatorImpl calculator = new CalculatorImpl();//代理类实例化CalculatorProxy proxy = new CalculatorProxy(calculator);//通过代理类的实例,传递到目标类的目标方法,且实现了执行目标方法外围包了一层增强代码int result = proxy.add(2,3);}
}

output:

preCalculator
result is 5
postCalculatorProcess finished with exit code 0

这样实现的好处,是可以在执行目标方法的前后,自由包裹增强代码,此类实现方式也就是静态代理。

缺点是: 每个类都需要创建一个代理类,还得给代理类实例化,too annoying. 如果有方法可以自动创建代理类,甚至直接给代理类实例化就好啦!

2.java.lang.reflect.Proxy类

2.1 利用反射创建proxy类

jdk提供的java.lang.reflect.Proxy中getProxyClass方法可以实现自动创建代理类。

public static Class<?> getProxyClass(ClassLoader loader,Class<?>... interfaces)throws IllegalArgumentException

Returns the java.lang.Class object for a proxy class given a class loader and an array of interfaces. The proxy class will be defined by the specified class loader and will implement all of the supplied interfaces. If any of the given interfaces is non-public, the proxy class will be non-public. If a proxy class for the same permutation of interfaces has already been defined by the class loader, then the existing proxy class will be returned; otherwise, a proxy class for those interfaces will be generated dynamically and defined by the class loader.

说人话:

  • 方法实现了通过ClassLoader定义一个proxy类,实现给所有interface。1
  • 如果给的interface不是public的,则生成的proxy类也不是public的。
  • 如果给的interfaces的proxy类已经有了,直接拎出来返回
  • 如果对应的proxy类还没有,则动态生成
  • 返回结果是一个Object类型的proxy class

实现的思路是:
(1) 用getProxyClass获取/生成Proxy代理类
(2) 用Class类中getConstructor()方法获取代理类的构造函数,以便实例化代理类,需要提供入参类型
(3) 实例化代理类,将目标类的实例或者是可以实现目标类的目标方法的东东作为参数,传给代理类的实例。

Proxy类中唯一一个非static field,为InvocationHandler h,用作使用指定的代理指定的参数调用实例对象正在调用的方法,只要重写为InvocationHandler接口中invoke方法,即可代替

来吧,理论结合实践吧.

public interface Calculator {int add(int i, int j);
}
//目标类
public class CalculatorImpl implements Calculator {@Overridepublic int add(int i, int j) {return i + j;}
}
2.1.1 动态代理实现一

定义InvocationHandlerImpl类实现InvocationHandler接口,重写invoke方法。在invoke方法中实例化代理目标类CalculatorImpl

Object result = method.invoke(calculator1, args); 完成目标对象的方法的有参调用

import java.lang.reflect.*;public class mainTest {private static class InvocationHandlerImpl implements InvocationHandler {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {///return 666;CalculatorImpl calculator1 = new CalculatorImpl();System.out.println("pre calculator");Object result = method.invoke(calculator1, args);System.out.println(result);System.out.println("post calculator");return result;}}public static void main(String[] avrg) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {/*1. 静态代理实现CalculatorImpl calculator = new CalculatorImpl();System.out.println(calculator.getClass());System.out.println(calculator.getClass().getClassLoader());CalculatorProxy proxy = new CalculatorProxy(calculator);int result = proxy.add(2,3);*///2. getProxyClass方法获取代理类,入参为目标类的ClassLoader,和需要实现的interfaceClass CalculatorProxyClass = Proxy.getProxyClass(CalculatorImpl.class.getClassLoader(), Calculator.class);//获取以InvocationHandler类型为入参的代理类的构造函数,以便后面为代理类实例化Constructor CalculatorProxyClassCons = CalculatorProxyClass.getConstructor(InvocationHandler.class);InvocationHandlerImpl handler = new InvocationHandlerImpl();Calculator calculator = (Calculator) CalculatorProxyClassCons.newInstance(handler);calculator.add(1, 2);}}

运行到invoke()中method.invoke()时,会调用CalculatorImpl.add()

上述写法可改进的空间:

  1. InvocationHandlerImpl只有在实例化代理类的时候使用,可以作为匿名类实现,更简洁;
  2. InvocationHandle 写死了是代理CalculatorImpl类的,不够灵活。可以通过将需要代理的实例传参进invoke,而不是写死代理CalculatorImpl类。
2.1.2 动态代理实现二
import java.lang.reflect.*;public class mainTest {/*  private static class InvocationHandlerImpl implements InvocationHandler {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {///return 666;CalculatorImpl calculator1 = new CalculatorImpl();System.out.println("pre calculator");Object result = method.invoke(calculator1, args);System.out.println(result);System.out.println("post calculator");return result;}}*/public static void main(String[] avrg) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {/*1. 静态代理实现CalculatorImpl calculator = new CalculatorImpl();System.out.println(calculator.getClass());System.out.println(calculator.getClass().getClassLoader());CalculatorProxy proxy = new CalculatorProxy(calculator);int result = proxy.add(2,3);*///getProxyClass方法获取代理类,入参为目标类的ClassLoader,和需要实现的interfaceClass CalculatorProxyClass = Proxy.getProxyClass(CalculatorImpl.class.getClassLoader(), Calculator.class);//获取以InvocationHandler类型为入参的代理类CalculatorProxyClass的构造函数,以便后面为代理类实例化Constructor CalculatorProxyClassCons = CalculatorProxyClass.getConstructor(InvocationHandler.class);//InvocationHandlerImpl handler = new InvocationHandlerImpl();CalculatorImpl target = new CalculatorImpl();//通过代理类的构造函数实例化代理类Calculator calculator = (Calculator) CalculatorProxyClassCons.newInstance(new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("pre calculator");Object result = method.invoke(target,args);System.out.println(result);System.out.println("post calculator");return result;}});calculator.add(1, 2);}}

当调用calculator.add(1,2)时,JVM会自动导向InvocationHandler.invoke(), Object proxy为调用的proxy实例

2.1.3 动态代理实现三

除了使用getProxyClass获取/生成Proxy Class,再获取构造函数,在newInstance外,Proxy还提供了newProxyInstance方法,可直接生产代理类的实例。

import java.lang.reflect.*;public class mainTest {/*  private static class InvocationHandlerImpl implements InvocationHandler {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {///return 666;CalculatorImpl calculator1 = new CalculatorImpl();System.out.println("pre calculator");Object result = method.invoke(calculator1, args);System.out.println(result);System.out.println("post calculator");return result;}}*/public static void main(String[] avrg) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {/*1. 静态代理实现CalculatorImpl calculator = new CalculatorImpl();System.out.println(calculator.getClass());System.out.println(calculator.getClass().getClassLoader());CalculatorProxy proxy = new CalculatorProxy(calculator);int result = proxy.add(2,3);*///getProxyClass方法获取代理类,入参为目标类的ClassLoader,和需要实现的interface/* Class CalculatorProxyClass = Proxy.getProxyClass(CalculatorImpl.class.getClassLoader(), Calculator.class);//获取以InvocationHandler类型为入参的代理类CalculatorProxyClass的构造函数,以便后面为代理类实例化Constructor CalculatorProxyClassCons = CalculatorProxyClass.getConstructor(InvocationHandler.class);//InvocationHandlerImpl handler = new InvocationHandlerImpl();CalculatorImpl target = new CalculatorImpl();//通过代理类的构造函数实例化代理类Calculator calculator = (Calculator) CalculatorProxyClassCons.newInstance(new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("pre calculator");Object result = method.invoke(target,args);System.out.println(result);System.out.println("post calculator");return result;}});*/CalculatorImpl target = new CalculatorImpl();Calculator calculator = (Calculator) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("pre calculator");Object result = method.invoke(target,args);System.out.println(result);System.out.println("post calculator");return result;}});calculator.add(1, 2);}}

  1. 有关ClassLoader, 详见 ↩︎

[Java] 代理模式 Proxy Mode相关推荐

  1. Java代理设计模式(Proxy)的四种具体实现:静态代理和动态代理

    面试问题:Java里的代理设计模式(Proxy Design Pattern)一共有几种实现方式?这个题目很像孔乙己问"茴香豆的茴字有哪几种写法?" 所谓代理模式,是指客户端(Cl ...

  2. Java代理设计模式(Proxy)的具体实现:静态代理和动态代理

    Java代理设计模式(Proxy)的具体实现:静态代理和动态代理 实现方式一:静态代理 静态代理方式的优点 静态代理方式的缺点 Java动态代理实现方式一:InvocationHandler Java ...

  3. Java24种设计模式(第二种)--代理模式(Proxy Pattern)

    Java24种设计模式 (第二种) 一.代理模式(Proxy Pattern) 模式逻辑: 什么是代理模式呢?我很忙,忙的没空理你,那你要找我呢就先找我的代理人吧,那代理人总要知道 被代理人能做哪些事 ...

  4. 二十三种设计模式(第十二种)-----代理模式(Proxy)

    二十三种设计模式(第十二种)-----代理模式(Proxy) 尚硅谷视频连接https://www.bilibili.com/video/BV1G4411c7N4?from=search&se ...

  5. java代理模式(java代理模式和适配器模式)

    Java设计模式的中介者模式是怎样的? 如果对象之间的关系原本一目了然,中介对象的加入便是"画蛇添足". 来看下中介者模式的组成部分吧. 1) 抽象中介者(Mediator)角色: ...

  6. java代理模式总结

    Java代理模式根据代理类生成时间的不同,可以分为静态代理和动态代理,它如同中介机构,可以为目标类提供代理服务,以控制对对象的访问,目标类的任何方法在执行前都必须经过代理类,这样代理类就可以用来负责请 ...

  7. java代理模式实现

    java代理模式实现 @(代理模式)[静态代理,动态代理,InvocationHandler] java的代理模式 分为两种,静态代理和动态代理,学习下什么是代理和静态动态代理的作用. java代理模 ...

  8. java代理模式-原来你是这样的代理

    这几天在看一些框架源码时看到了一个很奇妙的设计模式,有种熟悉个感觉,一时想不出是什么模式,后面经过了解才知道是动态代理,就这样带着好奇心学习了这个模式,更深入了解代理会发现不仅有静态和动态,还有很多其 ...

  9. 阿里十年资深程序员吐血总结之Java代理模式

    阿里十年资深程序员吐血总结之Java代理模式 文章目录 阿里十年资深程序员吐血总结之Java代理模式 1.接口代理 2.类代理 3.动态代理都是通过反射实现的吗 4.jdk动态代理和cglib动态代理 ...

最新文章

  1. Linux技术研究-基础篇(raid与LVM,配额)
  2. Java的反射作用_java反射机制的作用与优点
  3. mysql time转换输出_MySQL将timediff输出转换为日,时,分,秒格式?
  4. 3.第九章 树--9.3 二叉树结点类表示
  5. Tensorflow官方文档学习理解 (四)-深入MNIST
  6. Linux bash shell递归函数
  7. 双系统下如何切换到ubantu界面及如何切换到windows界面
  8. 购买阿里云服务器发布项目后外网无法访问的解决办法
  9. win10企业版2016长期服务版本认证过期怎么办?
  10. 分裂基 c语言算法,分裂基快速傅里叶变换 - osc_v8jmwk6w的个人空间 - OSCHINA - 中文开源技术交流社区...
  11. uniapp:轮播里如何加入视频
  12. 如何使用光盘启动计算机,如何从光驱启动?从光驱启动方法介绍【图文详解】...
  13. Apollo星火计划学习笔记|L1 Apollo平台安装(2021年9月更新)
  14. 浪潮服务器开机没有信号输出,PLC输出指示灯已经点亮但是输出没有信号-工业支持中心-西门子中国...
  15. 一叶知秋:通过Incloud Rail感受浪潮超融合架构
  16. android 球面 旋转 坐标系,天球坐标系和地球坐标系-GPS定位原理及应用-电子发烧友网站...
  17. 一、flink基础之数据读取
  18. 同济大学高等数学下册第九章多元函数微分法及其应用以及每日一题
  19. 【双评价学习笔记2019】农业生产适宜性评价01·土地资源评价
  20. python学习(二)常用运算符

热门文章

  1. java毕业设计电力公司员工安全培训系统Mybatis+系统+数据库+调试部署
  2. 计算机丢失api-ms-win-crt-runtime-l1-1-0.dll快速解决方案
  3. win10安装sqlmap_Windows中安装sqlmap方法(附实战)
  4. BS架构调用TSC TTP-244 Pro条码打印机的常见问题及解决方案
  5. 软件开发需要测试员吗?
  6. 车联网应用之“财产保全”
  7. 对比学习中的4种经典训练模式
  8. sql 语句操作,修改字段中字符串的一部分
  9. Python数据分析学习系列 十一 时间序列
  10. js网页导出excel表格文件