【JavaEE进阶】 代理模式

news2025/5/21 6:29:06

文章目录

  • 🍃前言
  • 🎋什么叫代理模式
  • 🌴静态代理
  • 🎍动态代理
    • 🚩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.coloradmin.cn/o/1483316.html

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

相关文章

使用统一功能完善图书管理系统

目录 一、前提 二、实现强制登陆传统方式 三、拦截器 1、概念 2、拦截器 &#xff08;1&#xff09;定义拦截器 &#xff08;2&#xff09;注册拦截器 &#xff08;3&#xff09;运行 3、使用拦截器实现强制登陆 4、DispatcherServlet源码解析 四、适配器模式 1、适…

深入剖析k8s-控制器思想

引言 本文是《深入剖析Kubernetes》学习笔记——《深入剖析Kubernetes》 正文 控制器都遵循K8s的项目中一个通用的编排模式——控制循环 for {实际状态 : 获取集群中对象X的实际状态期望状态 : 获取集群中对象X的期望状态if 实际状态 期望状态 {// do nothing} else {执行…

协议-http协议-基础概念03-http状态码-http特点-http性能-压缩和分块传输-范围请求

参考来源&#xff1a; 极客时间-透视HTTP协议(作者&#xff1a;罗剑锋)&#xff1b; 01-状态码分类 开头的 Version 部分是 HTTP 协议的版本号&#xff0c;通常是HTTP/1.1&#xff0c;用处不是很大。后面的 Reason 部分是原因短语&#xff0c;是状态码的简短文字描述&#xff…

【计算机网络_应用层】TCP应用与相关API守护进程

需要云服务器等云产品来学习Linux的同学可以移步/–>腾讯云<–/官网&#xff0c;轻量型云服务器低至112元/年&#xff0c;优惠多多。&#xff08;联系我有折扣哦&#xff09; 文章目录 1. 相关使用接口2. 代码实现2.1 日志组件2.2 Server端2.3 Client端2.3 bug解决 3. 守…

c语言数据结构(5)——栈

欢迎来到博主的专栏——C语言数据结构 博主id&#xff1a;代码小豪 文章目录 栈栈的顺序存储结构栈的插入空栈的初始化栈的删除判断空栈读取栈顶元素数据 实现顺序栈的所有代码栈的链式存储结构链式栈的初始化链式栈的入栈操作链式栈的出栈操作 实现链式栈的所有代码 栈 栈是…

[微服务]Eureka注册中心

目录 1、引言 2、Eureka的结构和作用 2.1、图解 2.2、几个重要问题⭐ 3、搭建eureka-server 3.1.创建eureka-server服务 3.2、引入eureka依赖 3.3、编写启动类 3.4、编写配置文件 3.5、启动服务 4、服务注册(user) 4.1、引入依赖 4.2、配置文件 4.3、启动多个use…

python--练习题

1.python是一种&#xff08; &#xff09;类型的编程语言 A.机器语言 B.解释 C.编译 D.汇编语言 答案&#xff1a;B 2.python语言print(中国&#xff0c;你好)的输出是&#xff08;&#xff09; A.(中国&#xff0c;你好&#xff09; B.中国&#xff0c;你好 C.中国&#xff0c…

【前端素材】推荐优质后台管理系统网页Star admin平台模板(附源码)

一、需求分析 1、系统定义 后台管理系统是一种用于管理和控制网站、应用程序或系统的管理界面。它通常被设计用来让网站或应用程序的管理员或运营人员管理内容、用户、数据以及其他相关功能。后台管理系统是一种用于管理网站、应用程序或系统的工具&#xff0c;通常由管理员使…

吴恩达机器学习全课程笔记第五篇

目录 前言 P80-P85 添加数据 迁移学习 机器学习项目的完整周期 公平、偏见与伦理 P86-P95 倾斜数据集的误差指标 决策树模型 测量纯度 选择拆分方式增益 使用分类特征的一种独热编码 连续的有价值特征 回归树 前言 这是吴恩达机器学习笔记的第五篇&#xff0c…

Redis 的 介绍 及 使用

redis 简介 简单来说 redis 就是一个数据库&#xff0c;不过与传统数据库不同的是 redis 的数据是存在内存中的&#xff0c;所以读写速度非常快&#xff0c;因此 redis 被广泛应用于缓存方向。另外&#xff0c;redis 也经常用来做分布式锁。redis 提供了多种数据类型来支持不同…

springboot3.x 以上,官方不建议使用spring.factories

springboot2.7.x 以上,官方不建议使用spring.factories 最近公司项目升级.需要将springcloud/springboot版本升级到2.7.x以上,再升级的过程中遇到了太多的问题.总结在了如下文章中: springboot艰难版本升级之路!! springboot 2.3.x版本升级到2.7.x版本 这篇文章就重点是梳理一…

npm digital envelope routines::unsupported

问题描述&#xff1a;npm运行命令报错&#xff1a;digital envelope routines::unsupported 原因&#xff1a;node版本过高 解决方案&#xff1a;在运行命令之前加上 SET NODE_OPTIONS--openssl-legacy-provider && SET NODE_OPTIONS--openssl-legacy-provider &&a…

vSphere资源管理

一 内存、CPU、资源池和vApp 内存部分&#xff1a; 关联VM内存 我们可以超额的关联内存给VM。例如&#xff1a;ESXI物理主机内存只有8G&#xff0c;但我们可以给三个VM都分配4G内存。 2.ESXI四大高级内存控制技术 a.Page sharing&#xff08;透明的页面共享&#xff09; 虚…

PYTHON 自动化办公:压缩图片(PIL)

1、介绍 在办公还是学习过程中&#xff0c;难免会遇到上传照片的问题。然而照片的大小限制一直都是个问题&#xff0c;例如照片限制在200Kb之内&#xff0c;虽然有很多图像压缩技术可以实现&#xff0c;但从图像处理的专业来说&#xff0c;可以利用代码实现 这里使用的库函数是…

【深度学习笔记】5_4 池化层

注&#xff1a;本文为《动手学深度学习》开源内容&#xff0c;部分标注了个人理解&#xff0c;仅为个人学习记录&#xff0c;无抄袭搬运意图 5.4 池化层 回忆一下&#xff0c;在5.1节&#xff08;二维卷积层&#xff09;里介绍的图像物体边缘检测应用中&#xff0c;我们构造卷…

python 使用curl_cffi 绕过jax3指纹-Cloudflare 5s盾

现在越来越多的网站已经能够通过JA3或者其他指纹信息&#xff0c;来识别你是不是爬虫了。传统的方式比如换UA&#xff0c;加代理是没有任何意义了&#xff0c;所以这个时候我们就需要使用到curl_cffi 了。 1.TLS 指纹是啥&#xff1f; 在绝大多数的网站都已经使用了 HTTPS&am…

【YOLO v5 v7 v8 小目标改进】ODConv:在卷积核所有维度(数量、空间、输入、输出)上应用注意力机制来优化传统动态卷积

ODConv&#xff1a;在卷积核所有维度&#xff08;数量、空间、输入、输出&#xff09;上应用注意力机制来优化传统的动态卷积 提出背景传统动态卷积全维动态卷积效果 小目标涨点YOLO v5 魔改YOLO v7 魔改YOLO v8 魔改 论文&#xff1a;https://openreview.net/pdf?idDmpCfq6Mg…

电商小程序10分类管理

目录 1 分类数据源2 搭建功能3 创建变量读取数据4 绑定数据总结 本篇我们介绍一下电商小程序的分类管理功能的开发&#xff0c;先看我们的原型图&#xff1a; 在首页我们是展示了四个分类的内容&#xff0c;采用上边是图标&#xff0c;下边是文字的形式。使用低代码开发&#…

Redis大数据统计

文章目录 一. 相关面试题1. 面试题一2. 面试题二 二. 统计的类型1. 聚合统计2. 排序统计3. 二值统计4. 基数统计 三. Hyperloglog1. 专业名词2. Hyperloglog使用3. Hyperloglog原理4. Hyperloglog案例 四. GEO1. 面试题2. GEO使用3. GEO案例 五. BitMap1. 面试题2. BitMap使用 …

Java+SpringBoot+Vue:招生宣传的全栈解决方案

✍✍计算机毕业编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java、…