温故知新之:代理模式,静态代理和动态代理(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.rhkb.cn/news/105780.html

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

相关文章

36、springboot --- 对 tomcat服务器 和 undertow服务器 配置访客日志

springboot 配置访客日志 ★ 配置访客日志&#xff1a; 访客日志&#xff1a; Web服务器可以将所有访问用户的记录都以日志的形式记录下来&#xff0c;主要就是记录来自哪个IP的用户、在哪个时间点、访问了哪个资源。 Web服务器可将所有访问记录以日志形式记录下来&#xff…

VMware 修改ip地址 虚拟机静态ip设置 centos动态ip修改为静态ip地址 centos静态ip地址 vmware修改ip地址

虚拟机的centos服务器经常变换ip&#xff0c;测试起来有些麻烦&#xff0c;故将动态ip修改为静态ip 1. 查看vmware 虚拟机网络配置&#xff1a; 点击编辑&#xff0c;打开虚拟网络配置 2. 选中nat模式&#xff0c;点击nat设置&#xff0c;最终获取网关ip: 192.168.164.2 3. 进…

CleanMyMac2024永久版Mac清理工具

Mac电脑作为相对封闭的一个系统&#xff0c;它会中毒吗&#xff1f;如果有一天Mac电脑产生了疑似中毒或者遭到恶意不知名攻击的现象&#xff0c;那又应该如何从容应对呢&#xff1f;这些问题都是小编使用Mac系统一段时间后产生的疑惑&#xff0c;通过一番搜索研究&#xff0c;小…

CK-GW06-E03与汇川PLC的EtherNet/IP通信

准备阶段&#xff1a; CK-GWO6-E03网关POE交换机网线汇川PLC编程软件汇川AC801-0221-U0R0型号PLC 1.打开汇川PLC编程软件lnoProShop(V1.6.2)SP2 新建工程&#xff0c;选择对应的PLC型号&#xff0c;编程语言选择为“结构化文本&#xff08;ST&#xff09;语言”&#xff0c;然…

线性代数(五) 线性空间

前言 《线性代数(三) 线性方程组&向量空间》我通过解线性方程组的方式去理解线性空间。此章从另一个角度去理解 空间是什么 大家较熟悉的&#xff1a;平面直角坐标系是最常见的二维空间 空间由无穷多个坐标点组成 每个坐标点就是一个向量 反过来&#xff0c;也可说&…

kafka--技术文档--架构体系

架构体系 Kafka的架构体系包括以下几个部分&#xff1a; Producer. 消息生产者&#xff0c;就是向Kafka broker发送消息的客户端。Broker. 一台Kafka服务器就是一个Broker。一个集群由多个Broker组成。一个Broker可以容纳多个Topic。Topic. 可以理解为一个队列&#xff0c;一…

Oracle 如何给大表添加带有默认值的字段

一、讲故事 你是否遇到过开发人员添加字段&#xff0c;导致数据库锁表问题&#xff1f; 但是令开发疑惑的事&#xff0c;他们添加字段&#xff0c;有的时候很快&#xff0c;有的时候很慢&#xff1f; 为什么呢&#xff1f; 询问得知&#xff0c;**加的慢时候是带上了default默…

【洛谷】P2440 木材加工

原题链接&#xff1a;https://www.luogu.com.cn/problem/P2440 1. 题目描述 2. 思路分析 整体思路&#xff1a;二分答案 设置一个变量longest来记录最长木头的长度&#xff0c;sum记录切成的小段数量之和。 令左边界l0&#xff0c;右边界llongest。 写一个bool类型的check…

【云原生】Docker的数据管理(数据卷、容器互联)

目录 一、数据卷&#xff08;容器与宿主机之间数据共享&#xff09; 二、数据卷容器&#xff08;容器与容器之间数据共享&#xff09; 三、 容器互联&#xff08;使用centos镜像&#xff09; 总结 用户在使用Docker的过程中&#xff0c;往往需要能查看容器内应用产生的数据…

联合注入步骤

使用场景&#xff1a; 有回显&#xff0c;可以看到某些字段的回显信息 像下面的有具体的回显信息 一、判断注入位点 在原始的id&#xff08;参数&#xff09;的输入后面添加额外的条件 如果and 11 有结果&#xff0c;and10没有结果输出&#xff0c; 就说明我们添加的额外条件…

2023最新AI创作系统ChatGPT网站源码V2.6.0+详细图文搭建安装教程/GPT联网/支持ai绘画+Dall-E2绘画/支持MJ以图生图

一、AI系统 如何搭建部署AI创作ChatGPT系统呢&#xff1f;小编这里写一个详细图文教程吧&#xff01; SparkAi使用Nestjs和Vue3框架技术&#xff0c;持续集成AI能力到AIGC系统&#xff01; 程序核心功能 程序已支持ChatGPT3.5/4.0提问、AI绘画、Midjourney绘画&#xff08;…

solidity0.8.0的应用案例12:通用可升级合约UUPS

代理合约中选择器冲突(Selector Clash)的另一个解决办法:通用可升级代理(UUPS,universal upgradeable proxy standard)。代码由OpenZeppelin的UUPSUpgradeable简化而成,不应用于生产。 UUPS 作为透明代理的替代方案,UUPS也能解决"选择器冲突"(Selector Cl…

论文阅读_模型结构_LoRA

name_en: LoRA: Low-Rank Adaptation of Large Language Models name_ch: LORA&#xff1a;大语言模型的低阶自适应 paper_addr: http://arxiv.org/abs/2106.09685 date_read: 2023-08-17 date_publish: 2021-10-16 tags: [‘深度学习’,‘大模型’] author: Edward J. Hu cita…

2023谷歌开发者大会直播大纲「初稿」

听人劝、吃饱饭,奉劝各位小伙伴,不要订阅该文所属专栏。 作者:不渴望力量的哈士奇(哈哥),十余年工作经验, 跨域学习者,从事过全栈研发、产品经理等工作,现任研发部门 CTO 。荣誉:2022年度博客之星Top4、博客专家认证、全栈领域优质创作者、新星计划导师,“星荐官共赢计…

【C++】开源:Box2D动力学库配置与使用

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍Box2D动力学库配置与使用。 无专精则不能成&#xff0c;无涉猎则不能通。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c…

EasyExcel自定义字段对象转换器支持转换实体和集合实体

文章目录 1. 实现ObjectConverter2. 使用3. 测试3.2 导出excel3.1 导入excel 1. 实现ObjectConverter package com.tophant.cloud.common.excel.converters;import cn.hutool.json.JSONUtil; import com.alibaba.excel.converters.Converter; import com.alibaba.excel.enums.…

远程连接虚拟机中ubuntu报错:Network error:Connection refused

ping检测一下虚拟机 可以ping通&#xff0c;说明主机是没问题 #检查ssh是否安装&#xff1a; ps -e |grep ssh发现ssh没有安装 #安装openssh-server sudo apt-get install openssh-server#启动ssh service ssh startps -e |grep ssh检查一下防火墙 #防火墙状态查看 sudo ufw…

汽车电子笔记之:AUTOSA架构下的多核OS操作系统

目录 1、AUTOSAR多核操作系统 1.1、OS Application 1.2、多核OS的软件分区 1.3、任务调度 1.4、核间任务同步 1.5、计数器、报警器、调度表 1.6、自旋锁与共享资源 1.7、核间通信IOC 1.8、OS Object中元素交互 1.9、多核OS的启动与关闭 2、多核OS注意事项 2.1、最小…

Kaggle(3):Predict CO2 Emissions in Rwanda

Kaggle&#xff08;3&#xff09;&#xff1a;Predict CO2 Emissions in Rwanda 1. Introduction 在本次竞赛中&#xff0c;我们的任务是预测非洲 497 个不同地点 2022 年的二氧化碳排放量。 在训练数据中&#xff0c;我们有 2019-2021 年的二氧化碳排放量 本笔记本的内容&am…

云安全攻防(十三)之 使用minikube安装搭建 K8s 集群

使用minikube安装搭建 K8s 集群 Kubernetes 是一个可移植的、可扩展的开源平台&#xff0c;用于管理容器化的工作负载和服务&#xff0c;可促进声明式配置和自动化,一般来说K8s安装有三种方式&#xff0c;分别是Minikube装搭建 K8s 集群&#xff0c;特点是只有一个节点的集群&…