代理模式(Java实现)

代理模式是常见的设计模式之一,顾名思义,代理模式就是代理对象具备真实对象的功能,并代替真实对象完成相应操作,并能够在操作执行的前后,对操作进行增强处理。(为真实对象提供代理,然后供其他对象通过代理访问真实对象)

分为

  • 静态代理

  • 动态代理

    • jdk动态代理

    • cglib动态代理

静态代理

真实类和代理类要实现同一个接口,在代理类中实现真实类的方法同时可以进行真实类方法的增强处理,在一个代理类中就可以完成对多个真实对象的注入工作。

public interface IRentHouse {void rentHouse();
}
public class RentHouse implements IRentHouse {@Overridepublic void rentHouse() {System.out.println("实现租房");}
}
public class IntermediaryProxy implements IRentHouse {private IRentHouse iRent;public IntermediaryProxy(IRentHouse iRentHouse) {iRent=iRentHouse;}@Overridepublic void rentHouse() {System.out.println("交中介费");iRent.rentHouse();System.out.println("中介负责维修管理");}
}
//client测试类
public class TestStaticProxy {public static void main(String[] args) {//定义租房IRentHouse iRentHouse = new RentHouse();//定义中介IRentHouse intermediaryProxy = new IntermediaryProxy(iRentHouse);//中介租房intermediaryProxy.rentHouse();}
}

动态代理

从静态代理的代码中可以发现,静态代理的缺点显而易见,那就是当真实类的方法越来越多的时候,这样构建的代理类的代码量是非常大的,所以就引进动态代理.

动态代理允许使用一种方法的单个类(代理类)为具有任意数量方法的任意类(真实类)的多个方法调用提供服务

JAVA 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 java 语言的反射机制。

jdk动态代理(接口代理)

Jdk代理涉及到java.lang.reflect包中的InvocationHandler接口和Proxy类,核心方法是

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 

jdk动态代理过程中实际上代理的是接口,是因为在创建代理实例的时候,依赖的是java.lang.reflect包中Proxy类的newProxyInstance方法,该方法的生效就恰恰需要这个参数;

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException{……
}

下面以案例来说明jdk动态代理的完整过程:

//接口
public interface Person {void wakeup();void sleep();
}
//实现类1
public class Student implements Person{private String name;public Student() {}public Student(String name) {this.name = name;}@Overridepublic void wakeup() {System.out.println("学生"+name+"早晨醒来啦");}@Overridepublic void sleep() {System.out.println("学生"+name+"晚上睡觉啦");}
}
//代理类
public class JDKDynamicProxy implements InvocationHandler {private Object bean;public JDKDynamicProxy(Object bean) {this.bean=bean;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {String methodname=method.getName();if (methodname.equals("wakeup")){System.out.println("早安~~~");}else if(methodname.equals("sleep")){System.out.println("晚安~~~");}return method.invoke(bean,args);}
}
//测试类
public class TestJDKDynamicProxy {public static void main(String[] args) {JDKDynamicProxy proxy = new JDKDynamicProxy(new Student("张三"));//创建代理实例Person student = (Person) Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[]{Person.class}, proxy);student.wakeup();student.sleep();}
}

输出结果为

早安~~
学生张三早晨醒来啦
晚安~~
学生张三晚上睡觉啦
接口中的方法,以及代理类中重写的invoke方法,但是invoke()方法并不是显式调用的,是在创建代理实例的过程中生成的接口虚拟代理类中调用了invoke方法。(把Sproxy0的实例强制转换成对应接口类型的引用,然后执行接口方法,进而执行代理类中invoke ()) 

总结对比:

1.静态代理中,代理类和真实类实现的是同一个接口,重写同样的方法;jdk动态代理中,代理类和真实类关系不大,代理类实现无侵入式的代码扩展。

2.静态代理中当接口中方法增加的时候,在代理类代码量也会增加,显然是不妥的;jdk动态代理解决了这个问题,当业务增加,代理类的代码不会增加。

3.jdk动态代理实现的是jdk自带InvocationHandler接口,实现了这个接口的类也叫拦截器类,也叫代理类。

cglib动态代理

从上面可以看出,jdk动态代理的前提条件是,要有接口存在,那还有许多场景是没有接口的,这个时候就需要cglib动态代理了,CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB通过继承方式实现代理。cglib动态代理过程中生成的是实现类的子类,cglib是如何凭空创造的实现类的子类的,下面是测试代码

//所需的代理类
public class CglibProxy implements MethodInterceptor {private Enhancer enhancer=new Enhancer();private Object bean;public CglibProxy(Object bean) {this.bean = bean;}public Object getProxy(){//设置需要创建子类的类enhancer.setSuperclass(bean.getClass());enhancer.setCallback(this);return enhancer.create();}@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {String methodName = method.getName();if (methodName.equals("wakeup")){System.out.println("早安~~~");}else if(methodName.equals("sleep")){System.out.println("晚安~~~");}return method.invoke(bean,objects);}
}
//测试类
public class TestCglibProxy {public static void main(String[] args) {//生成虚拟代理类的代码,本来虚拟代理子类是看不见的,//下面这句话的作用就是把执行过程中cglib增强后的class字节码文件System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\aop");CglibProxy proxy = new CglibProxy(new Cat("咪咪"));Cat cat = (Cat) proxy.getProxy();cat.wakeup();cat.sleep();}
}

总结:

cglib动态代理和jdk动态代理的区别显而易见,但是实现逻辑差不多,cglib代理类是通过实现MethodInterceptor,重写intercept方法,通过生成被代理类的子类来达到代理增强代码的目的;而Jdk代理是通过实现InvocationHandler,重写invoke方法,通过生成接口的代理类来达到代码增强的目的,所以jdk动态代理的实现需要接口,cglib则不需要,spring5.0以上以及springboot2.0以上默认采用cglib动态来实现AOP。

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

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

相关文章

threejs使用gui改变相机的参数

调节相机远近角度 定义相机的配置&#xff1a; const cameraConfg reactive({ fov: 45 }) gui中加入调节fov的方法 const gui new dat.GUI();const cameraFolder gui.addFolder("相机属性设置");cameraFolder.add(cameraConfg, "fov", 0, 100).name(…

YOLO格式数据集(.txt)如何转换为VOC格式数据集(.xml)

前言&#xff1a; 安装好python环境与编译器 转换&#xff1a; 将标注文件从文本格式&#xff08;.txt&#xff09;转换为 XML 格式&#xff08;.xml&#xff09;可以通过以下步骤完成&#xff1a; 解析文本标注文件&#xff1a;打开 .txt 文件&#xff0c;逐行读取每个标注…

Gin模板语法

Gin模板语法 文章目录 <center> Gin模板语法前提提醒Gin框架启动服务器模板解析模板渲染遇到不同目录下相同的文件如何加载和渲染自定义函数加载静态文件 前提提醒 由于有了前面template包的基础,所以该笔记不再过多详细分析 Gin框架启动服务器 语法: r:gin.Default()/…

Medical Isolated Power Supply System in Angola

安科瑞 华楠 Abstract: Diagnosis and treatment in modern hospitals are inseparable from advanced medical equipment, which are inseparable from safe and reliable power supply. Many operations often last for several hours, and the consequences of a sudden pow…

【UE4 RTS】07-Camera Boundaries

前言 本篇实现的效果是当CameraPawn移动到地图边缘时会被阻挡。 效果 步骤 1. 打开项目设置&#xff0c;在“引擎-碰撞”中&#xff0c;点击“新建Object通道” 新建通道命名为“MapBoundaries”&#xff0c;然后点击接受 2. 向视口中添加 阻挡体积 调整阻挡体积的缩放 向四…

【TypeScript】this指向,this内置组件

this类型 TypeScript可推导的this类型函数中this默认类型对象中的函数中的this明确this指向 怎么指定this类型 this相关的内置工具类型转换ThisParameterType<>ThisParameterType<>ThisType TypeScript可推导的this类型 函数中this默认类型 对象中的函数中的this…

华为OD机试-字符串序列判定

题目描述 给定两个字符串 s和 t &#xff0c;判断 s是否为 t 的子序列。 你可以认为 s 和 t 中仅包含英文小写字母。字符串 t 可能会很长&#xff08;长度n ~ 500,000&#xff09;&#xff0c;而 s 是个短字符串&#xff08;长度 <100&#xff09;。字符串的一个子序列是原…

Docker容器:docker基础及安装

文章目录 一.docker容器概述1.什么是容器2. docker与虚拟机的区别2.1 docker虚拟化产品有哪些及其对比2.2 Docker与虚拟机的区别 3.Docker容器的使用场景4.Docker容器的优点5.Docker 的底层运行原理6.namespace的六项隔离7.Docker核心概念 二.Docker安装 及管理1.安装 Docker1.…

【科研论文配图绘制】task1 掌握科研绘图的基本知识

【科研论文配图绘制】task1 掌握科研绘图的基本知识 写在最前 8月份Datawhale组队学习&#xff0c;写下该博客记录学习内容 1.科研论文配图的分类与构成 2.科研论文配图的格式和尺寸 3.科研论文配图中的字体和字号设置 4.科研论文配图的版式设计、结构布局和颜色搭配 占个…

机器学习笔记 - 基于C++的​​深度学习 三、实现成本函数

机器学习中的建模 作为人工智能工程师,我们通常将每个任务或问题定义为一个函数。 例如,如果我们正在开发面部识别系统,我们的第一步是将问题定义为将输入图像映射到标识符的函数F(X)。但是问题是如何知道F(X)公式? 事实上,使用公式或一系列固有规则来定义F(X)是不可行的(…

【Go 基础篇】Go语言指针解析:深入理解内存与引用的奥秘

介绍 指针是计算机编程中的重要概念&#xff0c;它提供了直接访问内存地址的能力&#xff0c;为程序的数据处理和内存管理提供了灵活性和效率。在Go语言&#xff08;Golang&#xff09;中&#xff0c;指针也是一种重要的数据类型&#xff0c;用于处理变量的引用和修改。本篇博…

GraphQL(六)登录态校验Directive

GraphQL Directive&#xff08;指令&#xff09;是GraphQL中的一种特殊类型&#xff0c;它允许开发者在GraphQL schema中添加元数据&#xff0c;以控制查询和解析操作的行为 Directive的详细说明及使用可见GraphQL&#xff08;五&#xff09;指令[Directive]详解 本文将介绍通过…

勘探开发人工智能技术:机器学习(6)

0 提纲 7.1 循环神经网络RNN 7.2 LSTM 7.3 Transformer 7.4 U-Net 1 循环神经网络RNN 把上一时刻的输出作为下一时刻的输入之一. 1.1 全连接神经网络的缺点 现在的任务是要利用如下语料来给apple打标签&#xff1a; 第一句话&#xff1a;I like eating apple!(我喜欢吃苹…

06 json数据解析和列表控件

内容回顾 json数据解析 json ----- 对要传输的数据进行封装的工具 json是由json数组([]) 和 json对象({})在qt中,对JSON数据进行处理(解析和打包) JSON数据处理所要包含的类: QJsonDocument -----它的作用是将数据转换成json文档 QJsonArray ---- json数组,就是封装多个…

User-Agent介绍

User-Agent介绍 引言 在Web开发中&#xff0c;我们经常会遇到需要根据不同的用户设备或浏览器类型来进行特定处理的情况。为了达到这样的目的&#xff0c;我们可以使用User-Agent这个HTTP头信息字段来识别用户的设备和浏览器。本篇文章将介绍User-Agent的基本概念、用法以及在…

SpringBoot 学习(02): 从嵌入式系统到嵌入式Servlet SpingBoot 的进化之路

嵌入式系统 计算机操作系统启动后&#xff0c;会加载一系列的功能和服务&#xff0c;而这些东西都不是开发操作系统的人写的&#xff0c;如果想让一个生态快速崛起&#xff0c;那么操作系统的开发人&#xff0c;就要告诉大家&#xff0c;在这个操作系统上&#xff0c;你要遵守…

3.1 Ansible 的使用和配置管理

Ansible 的使用和配置管理 文章目录 Ansible 的使用和配置管理Ansible 基础Ansible 模块和变量主机管理和组织角色和剧本部署应用和配置自动化与批量操作Ansible 常见用例Ansible 最佳实践和性能优化 大纲 Ansible 简介和特点 介绍 Ansible 的定义和作用&#xff0c;以及它在配…

【Java】Guava的Striped类。

Striped类,它提供了一种线程安全的分段锁(Striped Locking)机制。 Striped类可以用于将一组资源或操作分成多个段(Stripes),每个段上都有一个独立的锁。这种机制可以在并发访问时提供更好的性能,因为不同线程可以同时访问不同的段而不会相互阻塞。通常,Striped锁适用于…

pytorch3d成功安装

一、pytorch3d是什么&#xff1f; PyTorch3D的目标是帮助加速深度学习和3D交叉点的研究。3D数据比2D图像更复杂&#xff0c;在从事Mesh R-CNN和C3DPO等项目时&#xff0c;我们遇到了一些挑战&#xff0c;包括3D数据表示、批处理和速度。我们开发了许多有用的算子和抽象&#xf…

【Visual Studio Code】--- Win11 安装 VS Code 超详细

Win11 安装 VS Code 超详细 概述一、下载 Vscode二、安装 Vscode 概述 一个好的文章能够帮助开发者完成更便捷、更快速的开发。书山有路勤为径&#xff0c;学海无涯苦作舟。我是秋知叶i、期望每一个阅读了我的文章的开发者都能够有所成长。 一、下载 Vscode Vscode官网 二、…