温故知新之:代理模式,静态代理和动态代理(JDK动态代理)

0、前言

代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。

1、静态代理

静态代理是一种代理模式的实现方式,它在编译期间就已经确定了代理对象,需要为每一个被代理对象创建一个代理类。静态代理的实现比较简单,但是每个被代理对象都需要创建一个代理类,因此在代理对象比较多时,会导致代码几余和维护成本增加。

静态代理有两种实现,继承聚合两种模式。

1.1、继承模式

需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者继续相同父类,代理对象继承目标对象,重新目标对象的方法。

 目标对象:

package proxy.staticproxy.extends_model;//目标对象
public class UserService {public void login(){System.out.println("login success");}
}

代理类:

package proxy.staticproxy.extends_model;//代理对象
public class UserServiceProxy extends UserService{public void login(){System.out.println("开始执行--------------");super.login();}
}

 测试类:

package proxy.staticproxy;import proxy.staticproxy.extends_model.UserServiceProxy;
import proxy.staticproxy.implements_model.FactoryOne;
import proxy.staticproxy.implements_model.FactoryOneProxy;
import proxy.staticproxy.implements_model.IFactory;public class Test {@org.junit.Testpublic void extends_model(){UserServiceProxy proxy = new UserServiceProxy();proxy.login();}//  待代理类来处理/// 场景:当不想改动被代理类的业务逻辑,在处理开始和结束分别加上时间显示/// 处理核心逻辑:需要实现被代理类的接口及方法,在实现方法中田间需要添加的业务处理逻辑@org.junit.Testpublic void implements_model(){// 创建被代理类的对象IFactory word = new FactoryOne();// 创建代理类的对象IFactory proxyPaperFactory = new FactoryOneProxy(word);proxyPaperFactory.production();}// 直接调用被代理类业务处理@org.junit.Testpublic void test01(){// 创建被代理类的对象IFactory word = new FactoryOne();word.production();}
}

 执行结果:

开始执行--------------
login success

1.2、聚合模式

Subject:抽象主题角色,抽象主题类可以是抽象类,也可以是接口,是一个最普通的业务类型定义,无特殊要求。
RealSubject:具体主题角色,也叫被委托角色、被代理角色。是业务逻辑的具体执行者。
Proxy:代理主题角色,也叫委托类、代理类。它把所有抽象主题类定义的方法给具体主题角色实现,并且在具体主题角色处理完毕前后做预处理和善后工作。 

Subject 接口:

package proxy.staticproxy.implements_model;public interface IFactory {void production();
}

 RealSubject 类:

package proxy.staticproxy.implements_model;public class FactoryOne implements IFactory {@Overridepublic void production() {System.out.println(" 被代理类,开始初始化 ");System.out.println(" 生产笔记本、鼠标、键盘等等 ");System.out.println(" 被代理类处理完成 ");}
}

Proxy 类:

package proxy.staticproxy.implements_model;public class FactoryOneProxy implements IFactory {private IFactory factory; // 用被代理类对象进行实例化public FactoryOneProxy(IFactory factory) {this.factory = factory;}@Overridepublic void production() {System.out.println(" 代理开始工作 ,在此可以添加处理逻辑");factory.production();System.out.println(" 代理结束工作 ,在此可以添加处理逻辑");}
}

 测试类:

package proxy.staticproxy;import proxy.staticproxy.extends_model.UserServiceProxy;
import proxy.staticproxy.implements_model.FactoryOne;
import proxy.staticproxy.implements_model.FactoryOneProxy;
import proxy.staticproxy.implements_model.IFactory;public class Test {@org.junit.Testpublic void extends_model(){UserServiceProxy proxy = new UserServiceProxy();proxy.login();}//  待代理类来处理/// 场景:当不想改动被代理类的业务逻辑,在处理开始和结束分别加上时间显示/// 处理核心逻辑:需要实现被代理类的接口及方法,在实现方法中田间需要添加的业务处理逻辑@org.junit.Testpublic void implements_model(){// 创建被代理类的对象IFactory word = new FactoryOne();// 创建代理类的对象IFactory proxyPaperFactory = new FactoryOneProxy(word);proxyPaperFactory.production();}// 直接调用被代理类业务处理@org.junit.Testpublic void test01(){// 创建被代理类的对象IFactory word = new FactoryOne();word.production();}
}

运行结果:

 代理开始工作 ,在此可以添加处理逻辑被代理类,开始初始化 生产笔记本、鼠标、键盘等等 被代理类处理完成 代理结束工作 ,在此可以添加处理逻辑

2、动态代理

动态代理是一种代理模式的实现方式,它在运行期间根据需要动态生成代理对象,无需手动编写代理类,可以减少代码几余和维护成本。动态代理适用于需要代理的对象数量较多,代理类实现对灵活的场景,例Spring框架中的Spring AOP(面向切面编程)功能。

动态代理的实现方式也有两种,JDK动态代理CGLB动态代理两种模式。本文重点介绍JDK动态代理,

在JDK中,有一个Proxy类(名词,代理人)。Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态的生成实现类。Proxy类提供的有一个静态方法:newProxyInstance()方法给我们的目标对象(委托对象)返回一个代理对象。

核心方法:newProxyInstance方法的三个参数,按照顺序分别是 ClassLoader (类加载器),interfaces(一组接口,接口数组),InvocationHandler(调用处理器)。

ClassLoader (类加载器)

定义了由哪个classLoader对象来对生成的代理对象进行加载。

接口数组:

一个Interface对象的数组,表示将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了。

调用处理器:

一个InvocationHandler接口,表示代理实例的调用处理程序实现的接口。每个代理实例都具有一个关联的调用处理程席。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的 invoke 方法(传入InvocationHandler接口的子类)。

对象接口:

package proxy.dynamicproxy.v3;public interface IAnimal {public void run();public void eat();public void sleep();
}

被代理类<Cat>:

package proxy.dynamicproxy.v3;public class Cat implements IAnimal{@Overridepublic void run() {System.out.println("Cat Run invoking!!!");}@Overridepublic void eat() {System.out.println("Cat eat invoking!!!");}@Overridepublic void sleep() {System.out.println("Cat sleep invoking!!!");}
}

被代理类<Dog>: 

package proxy.dynamicproxy.v3;public class Dog implements IAnimal{@Overridepublic void run() {System.out.println("Dog Run invoking!!!");}@Overridepublic void eat() {System.out.println("Dog eat invoking!!!");}@Overridepublic void sleep() {System.out.println("Dog sleep invoking!!!");}
}

 代理类工具类:

package proxy.dynamicproxy.v3;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class ProxyUtils {public Object object;public ProxyUtils(Object object) {this.object = object;}public Object createProxyObj(){// 动态代理 顾名思义 针对接口动态生成代理类处理业务逻辑// 返回动态代理/*ClassLoader loader, 要实现接口的类加载器Class<?>[] interfaces,接口类InvocationHandler h 处理类* **/ClassLoader loader = object.getClass().getClassLoader();
//        Class<?>[] interfaces = new Class[]{argObj.getClass()};  // 当是接口Class<?>[] interfaces = object.getClass().getInterfaces(); // 当是类直接获取对应的接口方法;InvocationHandler handler = new IFactoryInvocationHandler();Object object = Proxy.newProxyInstance(loader, interfaces, handler);return object;}public class IFactoryInvocationHandler implements InvocationHandler {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("IFactoryInvocationHandler invoke Before!!!");Object rtn = method.invoke(object, args);System.out.println("IFactoryInvocationHandler invoke After!!!");return rtn;}}}

测试类:

package proxy.dynamicproxy;import proxy.dynamicproxy.v3.Cat;
import proxy.dynamicproxy.v3.IAnimal;
import proxy.dynamicproxy.v3.ProxyUtils;public class Test {@org.junit.Testpublic void v3_common_test() {// 实例化代理工具类ProxyUtils proxyUtils = new ProxyUtils(new Cat());// 创建代理对象IAnimal animal = (IAnimal)proxyUtils.createProxyObj();// 调用被代理类的方法animal.eat();System.out.println("========================================================");animal.run();System.out.println("========================================================");animal.sleep();System.out.println("========================================================");}
}

 运行结果:

IFactoryInvocationHandler invoke Before!!!
Cat eat invoking!!!
IFactoryInvocationHandler invoke After!!!
========================================================
IFactoryInvocationHandler invoke Before!!!
Cat Run invoking!!!
IFactoryInvocationHandler invoke After!!!
========================================================
IFactoryInvocationHandler invoke Before!!!
Cat sleep invoking!!!
IFactoryInvocationHandler invoke After!!!
========================================================Process finished with exit code 0

3、动态代理原理

JDK动态代理是一种实现代理模式的方式。它利用Java的反射机制,在运行时动态地创建代理对象,实现对目标对象的代理。

JDK动态代理的原理如下:
定义接口:首先需要定义一个接口,用于描述目标对象和代理对象的共同行为。
实现InvocationHandler接口:创建一个实现InvocationHandler接口的代理处理器类,该类负责对目标对象的方法进行代理。
获取代理类:通过java.lang.reflect.Proxy的静态方法newProxyInstance()创建代理类,该方法需要传入ClassLoader、接口数组和InvocationHandler实例。
调用代理对象:通过代理对象调用方法时,实际上是调用InvocationHandler的invoke()方法。
在invoke()方法中,可以进行一些额外的操作,比如在调用目标方法之前进行预处理、在调用目标方法后进行后处理等。

4、总结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/87838.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自定义拖拽功能,上下拖拽改变盒子高度

核心在于监听鼠标的move来改变div的高度&#xff0c;抽成了组件 <template><div ref"container" class"drag"><z-tooltip v-if"isShowIcon" effect"dark" content"格式化" placement"top-start"&…

深入理解ArrayList的动态扩容机制及应用

在java编程中&#xff0c;数据结构起着至关重要的作用&#xff0c;而ArrayList作为一种常用的动态数组&#xff0c;为我们在处理数据时提供了便利。其中&#xff0c;其独特的动态扩容机制更是为其赢得了广泛的应用。我们不管在工作还是面试中&#xff0c;都会遇到ArrayList&…

【腾讯云 TDSQL-C Serverless 产品测评】- 云原生时代的TDSQL-C MySQL数据库技术实践

一、活动介绍&#xff1a; “腾讯云 TDSQL-C 产品测评活动”是由腾讯云联合 CSDN 推出的针对数据库产品测评及产品体验活动&#xff0c;本次活动主要面向 TDSQL-C Serverless版本&#xff0c;初步的产品体验或针对TDSQL-C产品的自动弹性能力、自动启停能力、兼容性、安全、并发…

使用ctcloss训练矩阵生成目标字符串

首先我们需要明确 c t c l o s s ctcloss ctcloss是用来做什么的。比如说要生成的目标字符串长度为 l l l&#xff0c;而这个字符串包含 s s s个字符&#xff0c;字符串允许的最大长度为 L L L&#xff0c;这里认为一个位置是一个时间步&#xff0c;就是一拍&#xff0c;记为 T…

9个至少提升50%效率的VSCODE插件

在开始编码之前&#xff0c;您首先需要让您的工作流程适合您。让它更高效、更漂亮、更可定制。它会节省您大量的时间和精力&#xff0c;因此您将有更多的能力进行编码。 无论您是前端还是后端开发人员还是高级 Java 程序员&#xff0c;都没关系。这篇文章对你们大多数人来说仍然…

【rust/egui】(六)看看template的app.rs:TextEdit

说在前面 rust新手&#xff0c;egui没啥找到啥教程&#xff0c;这里自己记录下学习过程环境&#xff1a;windows11 22H2rust版本&#xff1a;rustc 1.71.1egui版本&#xff1a;0.22.0eframe版本&#xff1a;0.22.0上一篇&#xff1a;这里 TextEdit 文本编辑框 其定义为&#…

干货!证书超实用小Tips

1.CSA 是加拿大标准协会(Canadian Standards Association)的简称&#xff0c;它成立于1919年&#xff0c;是加拿大首家专为制定工业标准的非盈利性机构。在北美市场上销售的电子、电器等产品都需要取得安全方面的认证。 2.EAC认证 是海关联盟国家的认证。海关联盟是由俄罗斯…

【java】【springboot】【idea】springboot项目pom.xml 灰色下划线

解决方案&#xff1a; 这里我们找到了原因&#xff0c;就是因为选择了Ignored Files导致pom.xml文件被设置在maven忽略文件清单中&#xff0c;所以我们将打勾的选项取消&#xff0c;点击Apply,然后点击OK

Flutter问题记录 - Unable to find bundled Java version

新版本的Android Studio真的移除了JRE&#xff0c;jre目录找不到&#xff0c;怪不得报错了&#xff0c;不过多了一个jbr目录&#xff0c;找了个以前的Android Studio版本对比 搜了一下jbr&#xff08;JetBrains Runtime&#xff09;&#xff0c;原来IDEA老早就开始用了&#xf…

视频汇聚/视频云存储/视频监控管理平台EasyCVR安全检查的相关问题及解决方法

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

Python使用 YOLO_NAS_S 模型进行目标检测并保存预测到的主体图片

一、前言&#xff1a; 使用 YOLO_NAS_S 模型进行目标检测&#xff0c;并保存预测到的主体图片 安装包&#xff1a; pip install super_gradients pip install omegaconf pip install hydra-core pip install boto3 pip install stringcase pip install typing-extensions pi…

自动化PLC工程师能否转到c#上位机开发?

成功从自动化PLC工程师转向C#上位机开发的经历可能因人而异&#xff0c;以下是一些分享的思路和建议&#xff1a;扩展编程技能&#xff1a;学习C#语言和相关的开发工具和框架&#xff0c;掌握语言的基础知识和常用的编程技巧。可以通过在线教程、培训课程、书籍等途径进行学习&…