三种代理模式详解

article/2025/10/2 7:36:22

文章目录

二、代理模式(Proxy Pattern)

根据B站狂神视频整理:https://www.bilibili.com/video/BV1mc411h719?p=9
参考1:https://blog.csdn.net/kongsanjin/article/details/105419414
参考2:https://www.cnblogs.com/cenyu/p/6289209.html
参考3:https://blog.csdn.net/weixin_36759405/article/details/82770422

代理模式属于结构型模式

代理模式定义:为其他对象提供一种代理,以控制对这个对象的访问。代理对象起到中介作用,可去掉功能或者增加额外功能。

1、常见的几种代理模式:

远程代理,负责与远程JVM通信,以实现本地调用者与远程被调用者之间的正常交互。
虚拟代理,用来代替巨大对象,确保它在需要的时候才被创建。
保护代理,给被调用者提供访问控制,确认调用者的权限。
智能引用代理,比如火车票在各地都有售票处,房屋中介等。

以智能引用代理讲讲代理怎么实现的。有两种实现方式:静态代理和动态代理

2、静态代理

静态代理:代理和被代理对象在代理之前是确定的。它们都实现相同的接口或者继承相同的抽象类。

角色分析:

  • 抽象角色:一般使用接口或者抽象类
  • 真实角色:被代理的
  • 代理角色:代理真角色。代理真角色后会做一些附属操作
  • 客户:访问代理对象的人

代码

(1)接口类:Rent.java

//租房。抽象角色
public interface Rent {void rent();
}

(2)房东类:Host.java

//房东 真实角色
public class Host implements Rent{public void rent() {System.out.println("房东要出租房子了");}
}

(3)代理类:Proxy.java

//代理角色。代理房东租房
public class Proxy implements Rent{private Host host;public Proxy(){}public Proxy(Host host){this.host = host;}//租房操作,可以添加一些额外操作public void rent() {seeHouse();//看房host.rent();hetong();//签合同fare();//收中介费}public void seeHouse(){System.out.println("中介带你看房子");}public void hetong(){System.out.println("签订租赁合同");}public void fare(){System.out.println("收中介费");}
}

(4)测试类:Client.java

//租客。访问代理对象的人
public class Client {public static void main(String[] args) {Host host = new Host();//代理房东。可以加一些附属操作Proxy proxy = new Proxy(host);proxy.rent();}
}

静态代理简单总结:

根据上边代码可以看出,优点是在不修改房东类(被代理对象)的情况下,中介(代理对象)可以添加额外操作,比如看房,签合同等;缺点是中介和和房东都实现一样的接口,所以会有很多代理类,致命的是一旦接口中增加方法,实现这个接口的房东和中介都要做出修改。

怎么解决?使用动态代理

动态代理有两类,一是基于接口的JDK动态代理,另外一种是基于类的CGLib代理

3、JDK动态代理

代理对象不用实现接口,是利用JDK的API生成的,动态在内存中构建代理对象(需要我们指定)

代理类所在包:java.lang.reflect.Proxy

newProxyInstance方法
在这里插入图片描述

参数:

loader - 类加载器来定义类
interfaces - 代理类实现的接口
h - 调度方法动用的处理函数

上边是jdk-api上的,可能看的不是很懂,下边单独说一些,最好结合下边的JDKProxy类来看。

首先,JDKProxy类要实现InvocationHandler接口,而这个接口只有一个invoke方法,我们要重写这个方法,在里面写上我们的逻辑;

然后怎么生成代理类呢?就需要newProxyInstance方法了,参数详细介绍如下。

//处理代理实例上的方法调用并返回结果。
public Object invoke(Object proxy, //调用该方法的代理实例Method method, //要执行的目标对象的方法Object[] args) //执行方法需要的参数throws Throwable;//返回指定接口的代理类的实例。
public static Object newProxyInstance(ClassLoader loader,	  //指定当前目标对象使用的类加载器<?>[] interfaces,	 //目标对象实现的接口的类型InvocationHandler h   //事件处理器
)

代码如下:

接口Rent类和Host类是不变的,然后增加一个JDK动态代理类JDKProxy实现InvocationHandler,最后写测试类。

(1)代理类:JDKProxy.java

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** jdk动态代理,不需要实现接口,需要指定接口类型* 写法一,好理解,以租房为例的话,targetObject就是Rent接口*/
public class JDKProxy implements InvocationHandler {//需要代理的目标对象。//targetObject就是咱们的Rent接口public Object targetObject;//代理对象目标public void setTargetObject(Object targetObject) {this.targetObject = targetObject;}//生成得到代理类public Object getTargetObject(){/*** 返回代理对象* 参数一:指定当前目标对象使用的类加载器。* 参数二:目标对象实现的接口的类型。* 参数三:事件处理器。这里写的this是代表下边重写的invoke方法*/return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),targetObject.getClass().getInterfaces(),this);}/*** 实现InvocationHandler接口,就要重写invoke方法。* proxy,调用该方法的代理实例* method,要执行的目标对象的方法(利用反射的原理)* args,执行某方法需要的参数。*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {seeHouse();//看房//动态代理的本质,就是使用反射机制实现Object result = method.invoke(targetObject,args);hetong();//签合同fare();//收费return result;}public void seeHouse(){System.out.println("中介带你看房子");}public void hetong(){System.out.println("签订租赁合同");}public void fare(){System.out.println("收中介费");}
}

(2)测试类:client2.java

public class client2 {public static void main(String[] args) {//真实角色Host host = new Host();//代理角色,现在没有JDKProxy jdkProxy = new JDKProxy();//通过调用程序处理角色来处理我们要用调用的接口对象jdkProxy.setTargetObject(host);//把要代理的对象传过去Rent proxy = (Rent) jdkProxy.getTargetObject();proxy.rent();}
}

代码2

上边的代码是比较好理解的一种写法,下边的这种写法很简单,直接使用newProxyInstance,在它里面重写InvocationHandler方法(参考2博客中的)。

(1)代理工厂类:ProxyFactory.java

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** 创建动态代理对象* 动态代理不需要实现接口,但是需要指定接口类型*/
public class ProxyFactory {//目标对象private Object target;public ProxyFactory(Object target) {this.target = target;}//给目标对象生成代理对象public Object getProxyInstance() {return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {seeHouse();//执行目标对象方法Object returnValue = method.invoke(target, args);hetong();fare();return returnValue;}});}public void seeHouse(){System.out.println("中介带你看房子");}public void hetong(){System.out.println("签订租赁合同");}public void fare(){System.out.println("收中介费");}
}

(2)测试类:client3.java

public class client3 {public static void main(String[] args) {//目标对象Rent target = new Host();//给目标对象创建代理对象Rent proxy = (Rent) new ProxyFactory(target).getProxyInstance();//执行方法proxy.rent();}
}

代理对象不用实现接口,但目标对象(房东host)一定要实现接口(Rent),否则不能使用JDK动态代理。

4、CGLib代理

上边的静态代理和JDK动态代理都需要目标对象实现一个接口(Host实现Rent),但有时候,目标对象就是一个对象,没有实现任何接口,就不能使用JDK动态代理。那这时候可以使用CGLib代理。

CGLibb代理也叫子类代理,它是在内存中构建一个子类对象,从而实现对目标对象功能的扩展。

注意:

代理的类不能为final,否则会报错。

如果目标对象的方法为final或static,不会执行额外添加的功能。比如看房,签合同。

代码

需要导入CGLib的jar文件,但spring的核心已包括了CGLib的功能,可以直接导入spring的核心包。

<dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>5.2.9.RELEASE</version>
</dependency>

(1)CGLib代理工厂类:CGLibProxyFactory.java

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/*** CGLib子类代理工厂:内存中动态构建一个子类对象*/
public class CGLibProxyFactory implements MethodInterceptor {//目标对象private Object target;public CGLibProxyFactory(Object target) {this.target = target;}//给目标对象创建一个代理对象public Object getProxyInstance(){//1、工具类Enhancer en = new Enhancer();//2、设置父类en.setSuperclass(target.getClass());//3、设置回调函数en.setCallback(this);//4、创建子类(代理对象)return en.create();}@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {seeHouse();//看房//执行目标对象的方法Object returnValue = method.invoke(target, args);hetong();//签合同fare();//收费return returnValue;}public void seeHouse(){System.out.println("中介带你看房子");}public void hetong(){System.out.println("签订租赁合同");}public void fare(){System.out.println("收中介费");}
}

Enhancer是cglib中使用频率很高的一个类,它是一个字节码增强器,可以用来为无接口的类创建代理。

(2)测试类:client4.java

public class client4 {public static void main(String[] args) {//目标对象Host host = new Host();//生成代理对象Host proxy = (Host) new CGLibProxyFactory(host).getProxyInstance();//执行代理对象的方法proxy.rent();}
}

Spring在选择用JDK还是CGLiB的依据:

(1)当Bean实现接口时,Spring就会用JDK的动态代理

(2)当Bean没有实现接口时,Spring使用CGlib是实现

(3)可以强制使用CGlib,只需要在spring配置中加入

<aop:aspectj-autoproxy proxy-target-class="true"/>

5、CGLib和JDK动态代理的区别

(1)JDK动态代理是实现了被代理对象的接口,CGLib是继承了被代理对象。

(2)JDK和CGLib都是在运行期生成字节码,JDK是直接写Class字节码,CGLib使用ASM框架写Class字节码,CGLib代理实现更复杂,生成代理类比JDK效率低。

(3)JDK调用代理方法,是通过反射机制调用,CGLib是通过FastClass机制直接调用方法,CGLib执行效率更高。


http://chatgpt.dhexx.cn/article/ZN8ttpxm.shtml

相关文章

Spring的代理模式

1、代理模式 为什么要学习代理模式&#xff1f; 因为这就是springAOP的底层&#xff01;【springAOP和springMVC】 代理模式的分类&#xff1a; 静态代理动态代理 1.1、静态代理 角色分析&#xff1a; 抽象角色&#xff1a;一般会使用接口或者抽象类来解决真实角色&…

代理模式(Proxy模式)详解

在有些情况下&#xff0c;一个客户不能或者不想直接访问另一个对象&#xff0c;这时需要找一个中介帮忙完成某项任务&#xff0c;这个中介就是代理对象。例如&#xff0c;购买火车票不一定要去火车站买&#xff0c;可以通过 12306 网站或者去火车票代售点买。又如找女朋友、找保…

代理模式的详细介绍

国庆期间闲来无事&#xff0c;写了一个简单的小程序&#xff0c;小程序名称叫做 IT藏经楼。目的是分享这些年自己积累的一些学习材料&#xff0c;方面大家查找使用&#xff0c;包括电子书、案例项目、学习视频、面试题和一些PPT模板。里面所有材料都免费分享。目前小程序中只发…

代理模式

代理模式 代理模式应用场景模式结构实现方式 代理模式 控制着对于原对象的访问&#xff0c; 并允许在将请求提交给对象前后进行一些处理。 优点&#xff1a; 在客户端与目标对象之间起到一个中介作用和保护目标对象的作用&#xff1b;代理对象可以扩展目标对象的功能&#x…

代理模式详解

1. 代理模式 代理模式是一种比较好理解的设计模式。简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问&#xff0c;这样就可以在不修改原目标对象的前提下&#xff0c;提供额外的功能操作&#xff0c;扩展目标对象的功能。 代理模式一半包含三种角色&#x…

代理模式详细讲解

文章目录 一、什么是代理模式&#xff1f;二、 为什么使用代理模式&#xff1f;三、 代理模式的实现1、静态代理1.1、 创建公共的接口1.2、 创建被代理角色1.3、 创建代理角色1.4、 创建测试类 2、动态代理的实现2.1、 使用 JDK 的 Proxy 类实现动态代理1、 创建业务接口2、 创…

一文搞懂代理模式

代理模式 前言一、代理模式是什么&#xff1f;二、静态代理三、动态代理1.jdk动态代理&#xff08;接口代理&#xff09;2.cglib动态代理 前言 一、代理模式是什么&#xff1f; 代理模式是常见的设计模式之一&#xff0c;顾名思义&#xff0c;代理模式就是代理对象具备真实对象…

手机测试耳机音质的软件,耳机音质测试软件有哪些

耳机音质测试软件并不存在&#xff0c;因为耳机的音质对于人来说是主观的&#xff0c;你认为音质好的耳机&#xff0c;有的人却并不认为也很正常&#xff0c;国内外都没有恒定的耳机音质评判标准&#xff0c;大多数人认为音质好的耳机&#xff0c;那么它十有八九实际就是好的。…

软件测试的基本理论与方法

文章目录 前言软件测试基础1. 软件测试的概念2. 软件测试的目的 测试用例1. 测试用例的概念2. 测试用例的分类3. 测试用例的治理4. 测试用例的编制及使用5. 测试需求 软件生命周期1. 问题的定义及规划2. 需求分析3. 软件设计4. 程序编码5. 软件测试6. 运行维护7. 生命周期模型 …

固态硬盘测试软件有哪些,SSD测试软件有哪些?SSD测试软件盘点

在购买了固态硬盘(SSD)后&#xff0c;如果对商家或官方给出的诸如读写速度等关键性数据存在质疑的话&#xff0c;最好的解决方法莫过于通过SSD测试软件来找寻答案。那么&#xff0c;SSD测试软件有哪些&#xff1f;SSD测试软件哪个比较好用呢&#xff1f;针对上述问题&#xff0…

软件工程-软件测试-测试方法

软件工程-测试方法-白盒和黑盒测试 软件工程-软件测试 软件测试方法可以分为静态测试和动态测试。 静态测试 静态测试是指被测试程序不在程序上运行&#xff0c;而是采用人工检测和计算机辅助金泰分析的手段对程序进行检测。 静态测试方法 &#xff08;1&#xff09;人工检…

软件测试方法和技术有哪些?

软件测试方法和技术有哪些&#xff1f;包括软件测试基础、软件测试方法、软件测试流程和规范、单元测试与集成测试、系统测试、验收测试、软件本地化测试、测试自动化及其框架、白盒测试和黑盒测试等。 软件测试方法技术   软件测试方法&#xff1a; 一、等价类测试方法的…

软件测试方法汇总 - 从不同角度分析软件测试方法有哪些

1、从是否关心内部结构来看 &#xff08;1&#xff09;白盒测试&#xff1a;又称为结构测试或逻辑驱动测试&#xff0c;是一种按照程序内部逻辑结构和编码结构&#xff0c;设计测试数据并完成测试的一种测试方法。 &#xff08;2&#xff09;黑盒测试&#xff1a;又称为数据驱…

常见的软件测试方法有,常见的几种软件测试方法都有哪些

随着互联网的不断发展&#xff0c;越来越多的人也都开始学习软件测试的相关技术&#xff0c;而今天我们就一起来了解一下&#xff0c;常见的几种软件测试方法都有哪些。 1、单元测试 单元测试测试的是代码库的单元。 它们直接调用函数或单元&#xff0c;并确保返回正确的结果。…

Dynatrace系列之- 标记常见问题

Dynatrace系列之- 标记常见问题 在大型环境中&#xff0c;系统的某些方面可能会持续触发不必要的警报。这些告警可能来自非关键组件或者是非关键情况下的资源不足的问题。通常这些问题不需要人员响应。 为了减少此类警报并避免发出垃圾告警邮件&#xff0c;Dynatrace AI根因分…

什么是 Dynatrace 里的 Visually Complete 度量标准

Dynatrace 中的 Visually Complete 是一个度量标准&#xff0c;用于测量在加载过程中用户在页面上看到的内容。Visually Complete 指标是当一个用户看到页面上的所有重要元素并且它们正确地渲染时所测量的时间点。这意味着所有可见的文本、图像和视频都已加载并正确显示。该指标…

DevSecOps 团队请避免陷入这些可观测性陷阱

如果您发现难以管理跨越多个云运行不断变化的容器化工作负载的庞大基础架构&#xff0c;那么您并不孤单。 根据 Dynatrace 近期发布的一项研究&#xff0c;超过一半的组织的 DevSecOps 团队在可观测性数据方面感到痛苦。 多云和混合计算设置的兴起&#xff0c;使大部分组织能够…

前端性能分析工具Dyna Trace使用心得(转)

什么是dynatrace ajax “dynatrace ajax 是一个详细的底层追踪工具&#xff0c;它不仅可以显示所有请求和文件在网络中传输的时间&#xff0c;还会记录浏览器render&#xff0c;CPU消耗、JS解析和运行情况等详细的信息&#xff0c;而这些也只是dynatrace ajax的冰山一角。” 为…

使用dynatrace+showslow进行前端性能测试

原文&#xff1a;http://blog.csdn.net/zhangren07/article/details/6883617 1.背景 应用的性能测试与优化目前主要停留在服务器端的反馈&#xff0c;而对于前端性能标准的研究与测试相对比较空白&#xff0c;缺乏统一的标准与工具。众所周知&#xff0c;浏览器html组件的下载…

什么是 Dynatrace 里的 User Action

用户操作是与最终用户界面的交互&#xff0c;涉及对 Web 服务器的调用&#xff0c;这可能有多个嵌套调用。 它是由用户输入&#xff08;例如页面加载、单击或触摸&#xff09;触发的从一个视图到另一个视图的转换。 Web 应用的 User Action 类型&#xff1a; Load actionsXHR …