【JavaEE进阶】 代理模式

文章目录

  • 🍃前言
  • 🎋什么叫代理模式
  • 🌴静态代理
  • 🎍动态代理
    • 🚩JDK动态代理
    • 🚩CGLIB动态代理
  • ⭕总结

🍃前言

前面对Spring AOP的详细使用进行了介绍,这篇博客博主将详细讲解一下Spring AOP的原理,也就是Spring是如何实现AOP的.

Spring AOP是基于动态代理来实现AOP的,动态代理又是代理模式的一种

接下来我们一起来看看代理模式

🎋什么叫代理模式

代理模式,也叫委托模式.

定义:为其他对象提供⼀种代理以控制对这个对象的访问.它的作⽤就是通过提供⼀个代理类,让我们
在调⽤⽬标⽅法的时候,不再是直接对目标⽅法进行调用,而是通过代理类间接调用.

在某些情况下,⼀个对象不适合或者不能直接引⽤另⼀个对象,而代理对象可以在客⼾端和目标对象之
间起到中介的作用

使用代理前:
在这里插入图片描述
使用代理后:
在这里插入图片描述

生活中其实也存在着代理模式:

  • 艺人经纪⼈:光告商找艺⼈拍⼴告,需要经过经纪⼈,由经纪⼈来和艺⼈进行沟通.

  • 房屋中介:房屋进行租赁时,卖⽅会把房屋授权给中介,由中介来代理看房,房屋咨询等服务.

  • 经销商:⼚商不直接对外销售产品,由经销商负责代理销售.

  • 秘书/助理:合作伙伴找⽼板谈合作,需要先经过秘书/助理预约.

接下来我们来一起认识一下代理模式里的主要角色

  1. Subject:业务接⼝类.可以是抽象类或者接⼝(不⼀定有)

  2. RealSubject:业务实现类.具体的业务执⾏,也就是被代理对象.

  3. Proxy:代理类.RealSubject的代理

如果看成祖房

Subject:就是提前定义了房东做的事情,交给中介代理,也是中介要做的事情
RealSubject:房东
Proxy:中介

在这里插入图片描述

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

根据代理的创建时期,代理模式分为静态代理动态代理.

  • 静态代理:由程序员创建代理类或特定⼯具⾃动⽣成源代码再对其编译,在程序运⾏前代理类的
    .class⽂件就已经存在了.
  • 动态代理:在程序运⾏时,运⽤反射机制动态创建⽽成.

🌴静态代理

静态代理: 在程序运⾏前,代理类的.class⽂件就已经存在了.(在出租房⼦之前,中介已经做好了相关的
⼯作,就等租⼾来租房⼦了)

虽然静态代理也完成了对目标对象的代理,但是由于代码都写死了,对⽬标对象的每个⽅法的增强都是⼿动完成的,⾮常不灵活.所以⽇常开发⼏乎看不到静态代理的场景

如果目标对象新增其他业务,则需要我们手动进行修改,同样的,如果有新增接(Subject)和业务实现类(RealSubject),也需要对每⼀个业务实现类新增代理类(Proxy).

既然代理的流程是⼀样的,有没有⼀种办法,让他们通过⼀个代理类来实现呢?

这就需要⽤到动态代理技术了

🎍动态代理

相比于静态代理来说,动态代理更加灵活.

我们不需要针对每个目标对象都单独创建⼀个代理对象,而是把这个创建代理对象的⼯作推迟到程序运
行时由JVM来实现.也就是说动态代理在程序运行时,根据需要动态创建⽣成.

比如房屋中介,我不需要提前预测都有哪些业务,而是业务来了我再根据情况创建.

Java也对动态代理进⾏了实现,并给我们提供了⼀些API,常见的实现方式有两种:

  1. JDK动态代理

  2. CGLIB动态代理

🚩JDK动态代理

JDK动态代理类实现步骤

  1. 定义⼀个接⼝及其实现类(静态代理中的 HouseSubject 和 RealHouseSubject )
  2. ⾃定义 InvocationHandler 并重写 invoke ⽅法,在 invoke ⽅法中我们会调⽤⽬标⽅
    法(被代理类的⽅法)并⾃定义⼀些处理逻辑
  3. 通过 javaProxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) ⽅法创建代理对象

下面我们来进行实现以下:

  1. 定义JDK动态代理类

实现 InvocationHandler 接⼝

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
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 Thro
// 代理增强内容
System.out.println("我是中介, 开始代理");
    //通过反射调⽤被代理类的⽅法
    Object retVal = method.invoke(target, args);
//代理增强内容
System.out.println("我是中介, 代理结束");
return retVal;
}
}
  1. 创建⼀个代理对象并使用
public class DynamicMain {
    public static void main(String[] args) {
        HouseSubject target= new RealHouseSubject();
//创建⼀个代理类:通过被代理类、被代理实现的接⼝、⽅法调⽤处理器来创建
        HouseSubject proxy = (HouseSubject) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                new Class[]{HouseSubject.class},
                new JDKInvocationHandler(target)
        );
        proxy.rentHouse();
    }
}

对上述代码做一个简单的讲解:

  • InvocationHandler接是Java动态代理的关键接⼝之⼀,它定义了⼀个单⼀⽅法 invoke() ,用于处理被代理对象的方法调用.通过实现 InvocationHandler 接⼝,可以对被代理对象的方法进⾏功能增强.
  • Proxy 类中使⽤频率最高的⽅法是: newProxyInstance() ,这个⽅法主要⽤来⽣成⼀个代理对象
  • 这个⽅法⼀共有3个参数:
    • Loader:类加载器,⽤于加载代理对象.
    • interfaces:被代理类实现的⼀些接⼝(这个参数的定义,也决定了JDK动态代理只能代理实现了接⼝的⼀些类)
    • h:实现了InvocationHandler接⼝的对象

🚩CGLIB动态代理

JDK 动态代理有⼀个最致命的问题是其只能代理实现了接⼝的类.

有些场景下,我们的业务代码是直接实现的,并没有接⼝定义.为了解决这个问题,我们可以⽤CGLIB动
态代理机制来解决.

CGLIB(Code Generation Library)是⼀个基于ASM的字节码⽣成库,它允许我们在运⾏时对字节码进⾏
修改和动态⽣成.CGLIB通过继承⽅式实现代理,很多知名的开源框架都使⽤到了CGLIB.

例如:Spring中的AOP模块中:如果⽬标对象实现了接⼝,则默认采⽤JDK动态代理,否则采⽤CGLIB动态代理.

CGLIB动态代理类实现步骤

  1. 定义⼀个类(被代理类)
  2. ⾃定义 MethodInterceptor 并重写 intercept ⽅法, intercept ⽤于增强⽬标⽅法,和JDK动态代理中的 invoke ⽅法类似
  3. 通过Enhancer类的create()创建代理类

接下来一起来看一下实一个简单的实现:

  1. 添加依赖

和JDK动态代理不同,CGLIB(Code Generation Library)实际是属于⼀个开源项⽬,如果你要使用它
的话,需要⼿动添加相关依赖

<dependency>
	<groupId>cglib</groupId>
	<artifactId>cglib</artifactId>
	<version>3.3.0</version>
</dependency>
  1. ⾃定义MethodInterceptor(⽅法拦截器)

实现MethodInterceptor接口

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CGLIBInterceptor implements MethodInterceptor {
    //⽬标对象, 即被代理对象
    private Object target;
    public CGLIBInterceptor(Object target){
        this.target = target;
    }
    @Override
    public Object intercept(Object o, Method method, Object[] objects,
                            MethodProxy methodProxy) throws Throwable {
// 代理增强内容
        System.out.println("我是中介, 开始代理");
//通过反射调⽤被代理类的⽅法
        Object retVal = methodProxy.invoke(target, objects);
//代理增强内容
        System.out.println("我是中介, 代理结束");
        return retVal;
    }
}
  1. 创建代理类,并使用
public class DynamicMain {
    public static void main(String[] args) {
        HouseSubject target= new RealHouseSubject();
        HouseSubject proxy= (HouseSubject)
                Enhancer.create(target.getClass(),new CGLIBInterceptor(target));
        proxy.rentHouse();
    }
}

代码简单讲解如下:

  • MethodInterceptor 和JDK动态代理中的 InvocationHandler 类似,它只定义了⼀个方法 intercept() ,用于增强目标⽅法
  • Enhancer.create()用来⽣成⼀个代理对象
  • 参数说明:
    • type:被代理类的类型(类或接⼝)
    • callback:自定义⽅法拦截器MethodInterceptor

⭕总结

关于《【JavaEE进阶】 代理模式》就讲解到这儿,感谢大家的支持,欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

lottie加载带图片的json 预览

背景 产品看到一款app的动效很不错&#xff0c;让我去模仿实现。 第一步 获取apk中的静态资源 拿到这个app的apk后&#xff0c;直接使用压缩工具解压&#xff0c; assets文件夹就是静态资源的目录 静态资源里面有lottie 那么大部分的动效应该都是lottie实现的 网上找了很多…

Linux学习之信号

目录 1.信号的概念 2.信号的产生 3.信号的保存 4.信号的捕捉 信号的其它内容&#xff1a; SIGCHLD信号 1.信号的概念 在Linux中&#xff0c;信号是一种用于进程之间通信的基本机制。它是一种异步事件通知&#xff0c;用于通知进程发生了某些事件。如下是一些常见的Linux信…

DC-DC转换电路简介

DC-DC转换电路简介 1. 源由2. 工作原理3. 转换芯片4. DC-DC干扰5. DC-DC滤波5.1 PCB Layout5.2 电容滤波5.3 电感滤波 6. DC-DC电感/电容取值实验如何做&#xff1f;7. 参考资料 1. 源由 虽然说嵌入式系统涉及软件、硬件、机械、结构、网络等诸多领域内容。因此&#xff0c;在…

【MATLAB】 ICEEMDAN信号分解+FFT傅里叶频谱变换组合算法

有意向获取代码&#xff0c;请转文末观看代码获取方式~ 展示出图效果 1 ICEEMDAN信号分解算法 ICEEMDAN 分解又叫改进的自适应噪声完备集合经验模态分解&#xff0c;英文全称为 Improved Complete Ensemble Empirical Mode Decomposition with Adaptive Noise。 ICEEMDAN (I…

诊所门诊电子处方软件操作教程及试用版下载,医务室处方笺管理系统模板教程

诊所门诊电子处方软件操作教程及试用版下载&#xff0c;医务室处方笺管理系统模板教程 一、前言 以下软件程序教程以 佳易王诊所电子处方软件V17.0为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 如上图&#xff0c;点击基本信息设置——处方配…

一起去吃面条子吧

微风掠进窗沿&#xff0c;拂过愣在键盘上的指尖&#xff0c;正踌躇于命题的“||”还是“&&”。      突来的惬意&#xff0c;让人猛然惊醒&#xff0c;似是季节恍惚间悄然更替&#xff0c;那么这道命题索性就先放着。      毕竟实际编译运行结果&#xff0c;与…

实现定时器的两种方法:使用windows api定时器 和使用c++11/14 定时器

前言&#xff1a; 当我有一个开发需求&#xff0c;符合下面的条件 1.需要某个任务在程序中每隔一段时间就要执行一次&#xff0c;可能把这个任务封装成了一个函数。 2.这种需要定时执行的任务&#xff0c;有2个&#xff0c;3个....越来越多。 这个时候我们就可以考虑使用定时…

web基础03-JavaScript

目录 一、JavaScript基础 1.变量 2.输出 3.变量提升 4.区块 5.JavaScript数据类型 6.查看数值类型 7.undefined和null 8.布尔值 9.和的区别 10.算数/三元/比较/逻辑/赋值运算符 11.特殊字符 12.字符串 &#xff08;1&#xff09;获取字符串长度 &#xff08;2&am…

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的番茄成熟度检测系统(Python+PySide6界面+训练代码)

摘要&#xff1a;开发番茄成熟度检测系统对于提高农业产量和食品加工效率具有重大意义。本篇博客详细介绍了如何利用深度学习构建一个番茄成熟度检测系统&#xff0c;并提供了完整的实现代码。该系统基于强大的YOLOv8算法&#xff0c;并结合了YOLOv7、YOLOv6、YOLOv5的对比&…

SpringBoot约定大于配置

什么是约定大于配置 "约定大于配置"&#xff08;Convention Over Configuration&#xff09;是一种理念&#xff0c;旨在通过默认约定和规则来减少开发人员需要做的配置工作。在Spring Boot框架中&#xff0c;这一原则得到了充分应用&#xff0c;帮助开发者更快地构…

300分钟吃透分布式缓存-15讲:如何深入理解、应用及扩展 Twemproxy?

Twemproxy 架构及应用 Twemproxy 是 Twitter 的一个开源架构&#xff0c;它是一个分片资源访问的代理组件。如下图所示&#xff0c;它可以封装资源池的分布及 hash 规则&#xff0c;解决后端部分节点异常后的探测和重连问题&#xff0c;让 client 访问尽可能简单&#xff0c;同…

AI时代,我们需要什么能力?

AI 时代&#xff0c;一定会重构很多行业&#xff0c;也会重构人民的生活工作方式&#xff0c;那么 AI 时代&#xff0c;我们需要培养什么能力呢&#xff1f; 我们应该去做那些 AI 做不了的事情&#xff01;让 AI 成为我们的工具&#xff0c;助力我们更高效的解决问题&#xff…

Java - 获取汉字大写首字母输出

背景 有个项目需要将一批字符串的拼音首字母输出并大写&#xff0c;写了个工具类。 实现 需要引入外部jar。 <dependency><groupId>com.belerweb</groupId><artifactId>pinyin4j</artifactId><version>2.5.1</version> </dep…

C++之set、multiset

1、set简介 set是一种关联式容器&#xff0c;包含的key值唯一&#xff0c;所有元素都会在插入时自动被排序&#xff0c;其存储结构为红黑树。set只能通过迭代器(iterator)访问。 set和multiset的区别&#xff1a; &#xff08;1&#xff09;set不允许容器中有重复的元素&…

VUE3中的组件传值

一、父传子(props) 在子组件中可以使用defineProps接收父组件向子组件的传值 父组件fatherPage.vue&#xff1a; <template><div class"father"><button click"a a 1">按钮</button><childPage :a"a" /><…

在Windows系统上安装Docker和SteamCMD容器的详细指南有哪些?

在Windows系统上安装Docker和SteamCMD容器的详细指南有哪些&#xff1f; 安装Docker&#xff1a; 首先&#xff0c;需要在Windows操作系统上激活WSL2功能。这是因为Docker作为一个容器工具&#xff0c;依赖于已存在并运行的Linux内核环境。可以通过使用winget来安装Docker。具体…

禁止u盘拷贝的方法,U盘文件防止拷贝的方法

某大型制造企业在研发一款新产品时&#xff0c;涉及到了大量的机密数据和设计图纸。为了方便工作&#xff0c;研发部门的员工经常使用U盘在不同电脑之间传输数据。 然而&#xff0c;由于缺乏对U盘的有效管理&#xff0c;导致了一起严重的数据泄露事件。 事件经过&#xff1a;…

IEEE 802.11a协议

IEEE 802.11 系列协议主要使用了 OFDM 调制技术&#xff0c;是现今局域无线网的通用标准&#xff0c;被广泛应用于 WIFI 通信中&#xff0c;WIFI 版本及其对应的 802.11 协议版本如下&#xff1a; Wi-Fi 1 是 1999 年发布的 802.11b 标准。Wi-Fi 2 是 802.11a 标准&#xff0c…

Vue3_2024_2天【Vue3组合式setup用法及响应式ref和reactive】

第一&#xff1a;浅谈 | 不可不知 1.vue3目录介绍&#xff08;区别Vue2没有的&#xff09; vue3&#xff0c;默认使用ts语言&#xff0c;但是ts一开始无法识别某些文件&#xff0c;这里是系统默认配置&#xff1b; 2.vue2中的入口文件是main.js&#xff0c;而vue3这里的入口文…

【CSS】CSS简介,CSS基础选择器详解

目录 css简介 css语法规范 css代码风格&#xff1a; css选择器的作用 css基础选择器 标签选择器 类选择器 类选择器---多类名 id选择器 id选择器和类选择器的区别&#xff1a; 通配符选择器 总结 ⭐css简介 CSS 是层叠样式表 ( Cascading Style Sheets ) 的简称,也…