文章目录

  • 什么是代理模式
  • 代理的优缺点
  • 静态代理
  • 动态代理
  • InvocationHandler 接口 和 invoke 方法介绍
  • 静态代理和动态代理的区别

什么是代理模式

代理模式是常用的java设计模式,在Java中我们通常会通过new一个对象再调用其对应的方法来访问我们需要的服务。代理模式则是通过创建代理类(proxy)的方式间接地来访问我们需要的服务。

举一个生活中的例子:像我们在网上通过中介租到其背后房东的房子,因为房东也嫌麻烦想省事,此时中介就相当于代理而房东则是被代理,两者是分开的,这样我们就不会直接访问到房东,大部分情况下在中介手中租到的房子都会比原价要贵一些,这好比代理的作用,即不需要通过房东中介也可以在原有房价基础上进行增减或者添加其他的推广方式等操作来进行出租。

在Java中也是如此,我们需要遵循类的单一性原则,只有功能单一这个类被改动的可能性才会最小或者说在尽量不修改源码的前提下进行方法扩展,这样也可以避免在不清楚别人代码的情况下进行修改所导致的各种问题等等。


代理的优缺点

优点:

  • 可以提高程序灵活性和可扩展性。

  • 在不修改原代码的基础上,扩展和增强实现;

  • 代码解耦,在代理中通过参数可以判断真实类,做出不同的响应或调用;

  • 隐藏部分实现过程和细节,可以起到保护目标对象的作用

缺点:

  • 由于在客户端和真实对象之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢;

  • 实现代理模式需要额外的工作,有些代理模式的实现非常复杂。

  • 静态代理在委托类变多的情况时会显的非常臃肿,不方便阅读与使用


静态代理

由程序员创建或工具生成代理类的源码,再编译代理类,即代理类和委托类的关系再程序运行前就已经存在

实现步骤:

  1. 定义一个接口和接口的实现类

  2. 创建一个代理类同样的实现上述接口

  3. 将目标对象注入代理类中然后在代理类方法中调用目标类中的对应方法,这样我们就可以通过代理类在不修改原有方法的基础上进行扩展

代码实现:

/*** 目标接口*/
interface Hobby {//唱void sing();//跳void dance();}/*** 目标类*/
class MyHobby implements Hobby {@Overridepublic void sing() {System.out.println("sing...");}@Overridepublic void dance() {System.out.println("dance...");}
}/*** 代理类*/
class Hobbystaticproxy implements Hobby {Hobby hobby;public Hobbystaticproxy(Hobby hobby) {this.hobby = hobby;}@Overridepublic void sing() {rap();hobby.sing();rap();}@Overridepublic void dance() {rap();hobby.dance();rap();}public void rap() {System.out.println("static-rap...");}
}/*** main方法*/
class Test {public static void main(String[] args) {Hobby hobby = new MyHobby();Hobbystaticproxy hobbystaticproxy = new Hobbystaticproxy(hobby);hobbystaticproxy.sing();hobbystaticproxy.dance();}
}

输出结果:

可以看到我们在没有修改目标类的情况下通过代理类来实现按目标接口并且分别在目标类的 唱、跳方法前后都扩展了一个rap方法,这就是静态代理

缺点:接口类变化会影响实现类和代理类;比如方法修改返回值、参数类型、增加方法,实现类和代理类都需要修改,不灵活而且很麻烦。


动态代理

使用反射和字节码的技术,在运行期创建指定接口或类的子类,以及其实例对象,控制被代理对象的访问,使用的工具有 jdkproxy、cglibproxy 等。

上述静态代理在程序运行前就需要把对应的类和方法写好,这样就被写死了,这只是一个简单的接口里面也只有两个方法,那如果接口中有几十个方法都需要扩展呢,总不能一个个地手动去添加吧,所以有了我们的动态代理

实现步骤:

  1. 定义一个接口和接口的实现类

  2. 创建一个代理类实现InvocationHandler接口(指定运行时生成代理类需要完成的具体任务

  3. 重写InvocationHandler接口中的invoke方法

  4. 创建被代理类的对象,调用处理程序最后通过代理类对象来调用对应方法

代码实现:


/*** 目标接口*/
interface Hobby {void sing();void dance();}/*** 目标类*/
class MyHobby implements Hobby {@Overridepublic void sing() {System.out.println("sing...");}@Overridepublic void dance() {System.out.println("dance...");}}/*** 代理类*/
class HobbyDynamicProxy implements InvocationHandler{private final Object obj;public HobbyDynamicProxy(Object obj){this.obj = obj;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {rap();Object result = method.invoke(obj, args);rap();return result;}public void rap() {System.out.println("Dynamic-rap...");}
}/*** main方法*/
class Test {public static void main(String[] args) {InvocationHandler renterHandler = new HobbyDynamicProxy(new MyHobby());Hobby hobbyProxy = (Hobby)Proxy.newProxyInstance(Hobby.class.getClassLoader(), new Class[]{Hobby.class},renterHandler);hobbyProxy.sing();hobbyProxy.dance();}
}

输出结果:


InvocationHandler 接口 和 invoke 方法介绍

InvokationHandler是Java 反射包里面的一个接口通过用户类来实现,来激发一个动态代理类的方法。

它只有一个方法:

public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
  1. Object:实现方法的代理对象

  2. Method:代理实例激发的方法,Porxy参数中的接口方法

  3. Object[]:传递给方法的一系列参数


静态代理和动态代理的区别

静态代理:

在jvm运行之前就已经获取到代理类的class信息。代理类需要开发者自己写好,即开发者需要自己实现代理类的.java文件,也就是说在项目编译之前就需要存在代理类的.java文件,然后在编译阶段就可以将代理类的.java文件编译成.class文件,从而得到代理类的class信息;

动态代理:

不需要开发人员自己实现代理类的,也就是项目代码中是不存在代理类的.java文件的,既然代理类未由开发者实现,那么程序经过编译之后肯定也不会有代理类的.class文件。也就是说经过编译之后程序未启动运行之前,关于代理类的信息我们一无所知,它是在程序运行过程中需要用到的时候才会由jvm动态生成的,而且生成之后也只存在于内存中,不会写到磁盘保存成.class文件,更加不会保存为.java文件;

总之一句话就是静态代理是需要开发人员自己实现代理类的逻辑的,且代理类的class信息是在程序运行之前就已经可以获取到的了,而动态代理是不需要开发人员自己实现代理类的,

一篇文章让你搞懂Java中的静态代理和动态代理相关推荐

  1. 一篇文章带你搞懂Python中的类

    前言 今天我们要说的是面向对象的核心-----类,类能帮我们把复杂的事情变得有条理,有顺序,希望大家通过学习类能改善自己的编码风格,使代码变得更为好看,更加通俗易懂. 1.类的用法 一.什么是类 类( ...

  2. 一篇文章带你搞定 Java 中 @Target、@Documented 和 @Inherited 注释

    文章目录 一.@Target 二.@Documented 注释 三.@Inherited 注释 一.@Target 如果一个Annotation 没有明确地指明定义的位置,则可以在任意的位置使用,例如 ...

  3. 一篇文章带你搞懂网络层(网际层)-- 地址篇

    网络层(Network Layer)是OSI模型中的第三层(TCP/IP模型中的网际层),提供路由和寻址的功能,使两终端系统能够互连且决定最佳路径,并具有一定的拥塞控制和流量控制的能力.相当于发送邮件 ...

  4. java 自旋锁_搞懂Java中的自旋锁

    轻松搞懂Java中的自旋锁 前言 在之前的文章<一文彻底搞懂面试中常问的各种"锁">中介绍了Java中的各种"锁",可能对于不是很了解这些概念的同学 ...

  5. 一篇文章帮你搞定JVM中的堆

    文章目录 一篇文章帮你搞定JVM中的堆 堆的核心概述 堆的内存细分 设置堆内存大小与OOM OOM(OutOfMemory)举例 年轻代与老年代 图解对象分配过程 MinorGC,MajorGC,Fu ...

  6. 一篇文章带你搞懂 DEX 文件的结构

    From:https://blog.csdn.net/sinat_18268881/article/details/55832757 Dex文件格式详解:https://www.jianshu.com ...

  7. 教妹学Java(九):一文搞懂Java中的基本数据类型

    大家好,我是沉默王二,一个和黄家驹一样身高,和刘德华一样颜值的程序员.本篇文章通过我和三妹对话的形式来谈一谈"Java 中的数据类型". 教妹学 Java,没见过这么有趣的标题吧? ...

  8. 一篇文章带你搞懂微信小程序的开发过程

    点击上方"前端进阶学习交流",进行关注 回复"前端"即可获赠前端相关学习资料 今 日 鸡 汤 只解沙场为国死,何须马革裹尸还. 大家好,我进阶学习者. 前言 小 ...

  9. Java基础学习系列--(七)彻底搞懂java中的【异常、线程】的使用

    第一章 异常 1.1 异常概念 异常,就是不正常的意思.在生活中:医生说,你的身体某个部位有异常,该部位和正常相比有点不同,该部位的功能将受影响.在程序中的意思就是: 异常 :指的是程序在执行过程中, ...

最新文章

  1. NeurIPS 2020论文接收列表公布,智源研究院35篇入围
  2. python基础教程多少钱-厦门厦禾路Python基础教程培训费用多少-泰兴市新闻
  3. Mybatis查询可能为null
  4. 【2021最新版】如何clean或者install Maven项目——IntelliJ IDEA系列教程
  5. Harmonious Graph CodeForces - 1253D(思维+并查集)
  6. 从部署 httpd 入手,理清 k8s 配置中的 containerPort、port、nodePort、targetPort
  7. vue.set的用法
  8. 95-34-035-Context-HeadContext和TailContext
  9. 爬虫:查找自己浏览器headers
  10. js后退一直停留在当前页面或者禁止后退
  11. ​「5G消息」的最新消息
  12. POI合并单元格后边框显示问题
  13. abaqus实例手册_ABAQUS例子问题手册目录.pdf
  14. Linux 离线安装本地rpm的命令
  15. 关于ListView的优化
  16. ASIL-汽车安全完整性等级
  17. Efficient Exchange DP 二维DP
  18. Spring AOP思想的理解和简单实现
  19. 写给新手的深度学习综述,收藏了
  20. Ubuntu 磁盘管理  命令行工具

热门文章

  1. playwright--登录识别验证码实例
  2. 如何使用Pytest生成一份完美的测试报告
  3. 如何建立自己的技术壁垒
  4. 数据中心电气施工工序工艺管理要点
  5. 计算机程序的各个段【数据段、代码段等】
  6. linux ab压力测试
  7. docker视频学习总结
  8. 读取STM32F207/40x的CPU唯一ID(Unique Device ID)号方法
  9. redhatlinux9跟我学习安装配置RedHat9.02
  10. 计算机网络基础之Internet(因特网)