【代理模式】了解篇:静态代理 动态代理~

news2024/9/26 5:13:10

目录

1、什么是代理模式?

2、静态代理

3、动态代理

3.1 JDK动态代理类

3.2 CGLIB动态代理类

 4、JDK动态代理和CGLIB动态代理的区别?


1、什么是代理模式?

定义:

        代理模式就是为其他对象提供一种代理以控制这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象就可以在客户端和目标对象之间起到中介的作用。类似于租房:租户和房东之间现在不直接沟通,找了中介来联系,那么中介就是代理,这种模式就是代理模式。

        代理模式分为静态代理动态代理

2、静态代理

        在静态代理中,我们对目标对象的每个方法的增强都是手动完成的,非常不方便(比如接口一旦增加新方法,目标对象和代理对象都要进行修改)同时也麻烦(需要对于每个目标类都单独写一个代理类,类似于房东有很多套房子,每套房子都要找一个中介来代理),因此实际场景中静态代理的使用非常少。

        (1)从JVM的层面上讲:静态代理是在编译的时候就将接口、实现类、代理类等都变成了一个个实际的class文件。

模拟租户和房东之间的租房业务:

静态代理的使用步骤:

(1)创建一个接口和实现类——相当于房主现在要出租房;

//定义接口
public interface SellHouseService {
    void sell();
}

 不过房主有很多套房子,现在只想出租房子一;

//实现接口:具体的房东要出租房子
public class SellHouseOneService implements SellHouseService{
    @Override
    public void sell() {
        System.out.println("SellHouseService...");
    }
}

(2)创建一个代理类也实现这个接口 ——房主将房子一出租的任务交给中介,不然中介也没有权限去给租户看房子。

//创建代理类
public class StaticProxy implements SellHouseService{
    //将目标对象注入到代理类(),然后在代理类的对应方法调用目标类中的对应方法
    private final SellHouseService sellHouseService;
    public StaticProxy(SellHouseService sellService){
        this.sellHouseService = sellService;
    }
    @Override
    public void sell() {
        System.out.println("before...");
        sellHouseService.sell();
        System.out.println("after...");
    }
}

(3)主函数

public class Main {
    public static void main(String[] args) {
        //创建目标对象:房东
        SellHouseService service = new SellHouseOneService();
        //创建代理对象:中介
        SellHouseService proxy = new StaticProxy(service);
        proxy.sell();
    }
}

当我租第二套房子,第三套的时候也要找一个代理...非常麻烦。这个时候我们就使用动态代理了。

3、动态代理

相比于静态代理,动态代理更加灵活,我们不用再针对每个目标类都单独去创建一个代理类了。

小Tips

(1)动态代理主要有两种:JDK动态代理和CGLIB动态代理机制。

(2)其中,Spring AOP的实现就依赖了动态代理。

(3)从JVM角度讲:动态代理是在运行的时候动态生成类字节码,并加载到JVM中。

(4)在Java动态dialing机制中:InvocationHander接口和Proxy类是核心。

3.1 JDK动态代理类

JDK动态代理类的使用步骤:

(1)定义接口及实现类(同静态代理)

(2)自定义InvocationHandler并重写invoke方法,在invoke方法中调用被代理类的方法并定义一些处理逻辑;

//自定义InvokeHandler并重写invoke方法
public class JDKInvocationHandler implements InvocationHandler {
    //目标对象就是被代理对象
    private Object target;
    public JDKInvocationHandler(Object target){
        this.target = target;
    }
    //代理对象,要运行的方法,传递的实参
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //增强方法:前置处理
        //1、安全检查
        System.out.println("安全检查");
        //2、记录日志
        System.out.println("记录日志");
        //3.时间统计开始
        System.out.println("记录开始时间");

        //4、在invoke方法中会通过反射调用被代理类的方法
        Object retVal = method.invoke(target,args);
        //5、时间统计结束
        System.out.println("记录结束时间");
        return retVal;
    }
}

(3)创建一个代理类并使用。

public class Main {
    public static void main(String[] args) {
        //创建代理对象
        SellHouseService target = new SellHouseOneService();
        //创建一个代理类:通过被代理类、被代理实现的接口、方法调用处理器来创建
        SellHouseService proxy = (SellHouseService) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                new Class[]{SellHouseService.class},
                new JDKInvocationHandler(target)
        );
        proxy.sell();
    }
}

 小Tips

问:如何为Java对象创建一个代理对象?

        java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法;

(1)Public static Object newProxyInstance(ClassLoader loader,Class<?> [ ] interfaces,InvocationHandler h),newProxyInstance作用是生成一个代理对象。返回值就是代理;

(2)这个方法一共有三个参数:loader类加载器,用于加载代理对象;interfaces:被代理类实现的一些接口;还有实现了InvocationHanldler接口的对象。

(3)JDK动态代理的问题:只能代理实现了接口的类:因此使用CGLIB动态代理来解决。

(4)通过Proxy 类的 newProxyInstance() 创建的代理对象在调用方法的时候,实际会调用到实现InvocationHandler 接口的类的 invoke()方法。 你可以在 invoke() 方法中自定义处理逻辑,比如在方法执行前后做什么事情。 

3.2 CGLIB动态代理类

        CGLIB(Code Generation Library)允许我们在运行的时候对字节码进行修改和动态生成。CGLIB允许我们通过继承的方式实现代理。CGLIB动态代理机制中MethodIntercepor接口Enhancer类是核心。在Spring AOP的设计中,如果目标对象实现了接口,则默认采用JDK动态代理,否则使用CGLIB动态代理。

CGLIB动态代理类的使用步骤:

(1)添加依赖

	    <dependency>
			<groupId>cglib</groupId>
			<artifactId>cglib</artifactId>
			<version>3.3.0</version>
		</dependency>

(2)自定义MethodInterceptor并重写Intercept方法,intercept用于拦截增强被代理类的方法,和JDK动态代理中的Invoke方法类似;

public interface MethodInterceptor extends Callback{
    // 拦截被代理类中的⽅法
    public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,MethodProxy proxy) throws Throwable;
}
public class CGLIBInterceptor implements MethodInterceptor {
    //被代理对象
    private Object target;
    public CGLIBInterceptor(Object target){
        this.target = target;
    }
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        //1.安全检查
        System.out.println("安全检查");
        //2.记录⽇志
        System.out.println("记录⽇志");
        //3.时间统计开始
        System.out.println("记录开始时间");
        //通过cglib的代理⽅法调⽤
        Object retVal = methodProxy.invoke(target, args);
        //4.时间统计结束
        System.out.println("记录结束时间");
        return retVal;
    }
}

(3)通过Enhancer类的create()创建代理类并使用。

public static void main(String[] args) {
        SellHouseService target= new SellHouseOneService();
        SellHouseService proxy= (SellHouseService) Enhancer.create(target.getClass(),
                new CGLIBInterceptor(target));
        proxy.sell();
    }

 4、JDK动态代理和CGLIB动态代理的区别?

(1)JDK 动态代理只能代理实现了接⼝的类或者直接代理接⼝,⽽ CGLIB 可以代
理未实现任何接⼝的类。
(2)CGLIB 动态代理是通过⽣成⼀个被代理类的⼦类来拦截被代理类的⽅法调
⽤,因此不能代理声明为 final。

(3)性能: ⼤部分情况都是 JDK 动态代理更优秀,随着 JDK 版本的升级,这个优势更
加明显 

 

 

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

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

相关文章

图像 检测 - FCOS: Fully Convolutional One-Stage Object Detection (ICCV 2019)

FCOS: Fully Convolutional One-Stage Object Detection - 全卷积一阶段目标检测&#xff08;ICCV 2019&#xff09; 摘要1. 引言2. 相关工作3. 我们的方法3.1 全卷积一阶目标检测器3.2 FCOS的FPN多级预测3.3 FCOS中心度 4. 实验4.1 消融研究4.1.1 FPN多级预测4.1.2 有无中心度…

python学习时与chatgpt4对话的一些感悟

今天学SCENIC教程&#xff0c;看到里面有一句不是很懂 If you run this from a python script instead of a Jupyter notebook, please enclose the code in a if __name__ __main__: construct. 现在把和chatgpt4问答的内容发上来&#xff0c;确实是很厉害 没有太看懂&…

Verilog语法学习——LV6_多功能数据处理器

LV6_多功能数据处理器 题目来源于牛客网 [牛客网在线编程_Verilog篇_Verilog快速入门 (nowcoder.com)](https://www.nowcoder.com/exam/oj?page1&tabVerilog篇&topicId301) 题目 描述 根据指示信号select的不同&#xff0c;对输入信号a,b实现不同的运算。输入信号a…

蓝海卓越计费管理系统存在弱口令

连伟人的一生都充满了那么大的艰辛&#xff0c;一个平凡的人吃点苦又算得了什么呢&#xff1f; 漏洞描述 蓝海卓越计费管理系统存在弱口令漏洞 漏洞复现 访问漏洞url&#xff1a; 输入默认的账号密码&#xff1a;admin/admin 登录成功 文笔生疏&#xff0c;措辞浅薄&#…

小米手机MIUI优化的影响

1. 小/红米手机的MIUI优化选项 2. MIUI优化选项的影响 2.1 MIUI优化会影响应用信息展示 MIUI优化选项会影响到应用信息的内容展示&#xff0c;具体如下图所示&#xff1a; 如果我们需要在应用信息里展示自启动入口&#xff0c;那我们就需要开启MIUI优化。 2.2 MIUI优化会影…

C++对C的加强(全)

目录 C对C的加强 命名空间 为什么要使用命名空间 怎么使用命名空间 命名空间的定义 命名空间的使用 使用域解析符 :: 使用using声明 内联命名空间 嵌套命名空间 随时将新的成员加入命名空间 命名空间中 函数的声明和实现分开 无名命名空间 命名空间取别名 使用u…

苍穹外卖day08——地址簿+用户下单+订单支付(做不了)

导入地址簿——需求分析与设计 产品原型 接口设计 数据库设计 导入地址簿——代码导入 导入地址簿——功能测试 没有问题 用户下单——需求分析与设计 业务说明 业务流程 接口设计 数据库设计 用户下单——代码开发 DTO设计和VO设计 Controller层中 RequestMapping(&q…

Clock时钟电路PCB设计布局布线要求

时钟电路就是类似像时钟一样准确运动的震荡电路&#xff0c;任何工作都是依照时间顺序&#xff0c;那么产生这个时间的电路就是时钟电路&#xff0c;时钟电路一般是由晶体振荡器、晶振、控制芯片以及匹配电容组成&#xff0c;如图1所示。 图1 时钟电路 针对时钟电路PCB设计有以…

小白的机器学习之路(四)神经网络的初步认识:基于pytorch搭建自己的神经网络

小白的机器学习之路&#xff08;四&#xff09; 引子神经网络的基本结构反向传播算法和激活函数优化器如何通过pytorch搭建自己的BP network 引子 当前交通大数据业务的需要&#xff0c;需要承担一部分算法工作&#xff08;数据处理&#xff09;&#xff0c;考虑到上次研究深度…

用哪些指标可以抓住现货白银趋势?

在现货白银走势分类中&#xff0c;走势一般来说之分成三类&#xff0c;一个是上升&#xff0c;一个是下跌&#xff0c;还有一个是水平。对于投资者来说&#xff0c;趋势&#xff0c;也就是上升或者下跌是我们喜爱的&#xff0c;那么我们如何捕捉这种趋势呢&#xff1f;我们可以…

【雕爷学编程】MicroPython动手做(02)——尝试搭建K210开发板的IDE环境

知识点&#xff1a;简单了解K210芯片 2018年9月6日,嘉楠科技推出自主设计研发的全球首款基于RISC-V的量产商用边缘智能计算芯片勘智K210。该芯片依托于完全自主研发的AI神经网络加速器KPU,具备自主IP、视听兼具与可编程能力三大特点,能够充分适配多个业务场景的需求。作为嘉楠科…

Verilog语法学习——LV9_使用子模块实现三输入数的大小比较

LV9_使用子模块实现三输入数的大小比较 题目来源于牛客网 [牛客网在线编程_Verilog篇_Verilog快速入门 (nowcoder.com)](https://www.nowcoder.com/exam/oj?page1&tabVerilog篇&topicId301) 题目 描述 在数字芯片设计中&#xff0c;通常把完成特定功能且相对独立的…

C#之泛型

目录 一、概述 二、C#中的泛型 继续栈的示例 三、泛型类 &#xff08;一&#xff09;声明泛型类 &#xff08;二&#xff09;创建构造类型 &#xff08;三&#xff09;创建变量和实例 &#xff08;四&#xff09;比较泛型和非泛型栈 四、类型参数的约束 &#xff08;一…

系统集成中级计算汇总

基本计算&#xff1a; EV 挣值 (实际完成的工作量) AC 实际发生的花费 PV 计划花费(预算) CV 成本 SV 进度 CV 和 SV 的计算 都是通过EV 减去另一个值 CV EV-AC SV EV-PV 成本 chengben C 开头 所以CV 是成本 CV 中有个C 所以用到的是 AC ,另外一个则是剩余的PV CV SV 计算…

LeetCode621.Task-Scheduler<任务调度器>

题目&#xff1a; 思路&#xff1a; 思路个锤子,看完题根本不会写. 看的答案 : 【任务调度器】C 桶子_配图理解 - 任务调度器 - 力扣&#xff08;LeetCode&#xff09; 是一种贪心的思想.数学问题. 一个是任务的种类,一个是任务的最大的一个值。 代码是&#xff1a; //cod…

【组内工作】木马回联

文章目录 C2服务器安装和运行方法CrossC2运行方法sliver运行方法empire安装方法DeimosC2安装教程TrevorC2安装教程&#xff1a; C2服务器的流量特征CrossC21. 心跳包2. 命令3. ja3/ja3s Sliver1. http2. https empirehttphttps DeimosC2https TrevorC2 C2服务器安装和运行方法 …

【VTK】读取一个 STL 文件,并使用 Qt 显示出来,在 Windows 上使用 Visual Studio 配合 Qt 构建 VTK

知识不是单独的&#xff0c;一定是成体系的。更多我的个人总结和相关经验可查阅这个专栏&#xff1a;Visual Studio。 文章目录 A.hA.cppRef. 直接先把效果放出来&#xff0c;有需要就往下看。 A.h // A.h #pragma once#include <QtWidgets/QMainWindow> #include "…

【Qt】QML-02:QQuickView用法

1、先看demo QtCreator自动生成的工程是使用QQmlApplicationEngine来加载qml文件&#xff0c;下面的demo将使用QQuickView来加载qml文件 #include <QGuiApplication> #include <QtQuick/QQuickView>int main(int argc, char *argv[]) {QGuiApplication app(argc,…

蓝桥杯单片机第八届国赛 真题+代码

iic.c /* # I2C代码片段说明1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。2. 参赛选手可以自行编写相关代码或以该代码为基础&#xff0c;根据所选单片机类型、运行速度和试题中对单片机时钟频率的要求&#xff0c;进行代码调试和修改。 */ #include <STC1…

生态共建丨YashanDB与构力科技完成兼容互认证

近日&#xff0c;深圳计算科学研究院崖山数据库系统YashanDB V22.2与北京构力科技有限公司BIMBase云平台完成兼容性互认证。经严格测试&#xff0c;双方产品完全兼容、运行稳定。 崖山数据库系统YashanDB是深算院自主研发设计的新型数据库系统&#xff0c;融入原创理论&#xf…