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

目录

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{@Overridepublic void sell() {System.out.println("SellHouseService...");}
}

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

//创建代理类
public class StaticProxy implements SellHouseService{//将目标对象注入到代理类(),然后在代理类的对应方法调用目标类中的对应方法private final SellHouseService sellHouseService;public StaticProxy(SellHouseService sellService){this.sellHouseService = sellService;}@Overridepublic 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;}//代理对象,要运行的方法,传递的实参@Overridepublic 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;}@Overridepublic 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.mzph.cn/news/14207.shtml

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

相关文章

华为nat64配置

1.前期环境准备 环境拓扑 拓扑分为两个区域,左边为trust区域,使用IPv4地址互访,右边为untrust区域,使用IPv6地址互访 2.接口地址配置 pc1地址配置 pc2地址配置 FW接口配置 (1)首先进入防火墙配置界面 注:防火墙初始账号密码为user:admin,pwd:Admin@123,进入之后…

8.docker仓库

文章目录 Docker仓库本地私有仓库Docker HarborDocker harbor部署访问页面创建用户下载私有仓库镜像harbor同步 Docker仓库 本地私有仓库 ##先下载 registry 镜像docker pull registry##修改配置文件&#xff0c;在 daemon.json 文件中添加私有镜像仓库地址vim /etc/dock…

SQL-每日一题【1070. 产品销售分析 III】

题目 销售表 Sales&#xff1a; 产品表 Product&#xff1a; 编写一个 SQL 查询&#xff0c;选出每个销售产品 第一年 销售的 产品 id、年份、数量 和 价格。 结果表中的条目可以按 任意顺序 排列。 查询结果格式如下例所示&#xff1a; 示例 1&#xff1a; 解题思路 前置知…

Python爬虫的urlib的学习(学习于b站尚硅谷)

目录 一、页面结构的介绍  1.学习目标  2.为什么要了解页面&#xff08;html&#xff09;  3. html中的标签&#xff08;仅介绍了含表格、无序列表、有序列表、超链接&#xff09;  4.本节的演示 二、Urllib  1.什么是互联网爬虫&#xff1f;  2.爬虫核心  3.爬虫…

【MySQL】复合查询

复合查询目录 一、基本查询二、多表查询三、自连接四、子查询4.1 单行子查询4.2 多行子查询4.3 多列子查询4.4 在from子句中使用子查询4.5 合并查询4.5.1 union4.5.2 union all 五、实战OJ 一、基本查询 --查询工资高于500或岗位为MANAGER的雇员&#xff0c;同时还要满足他们的…

LLaMA模型论文《LLaMA: Open and Efficient Foundation Language Models》阅读笔记

文章目录 1. 简介2.方法2.1 预训练数据2.2 网络架构2.3 优化器2.4 高效的实现 3.论文其余部分4. 参考资料 1. 简介 LLaMA是meta在2023年2月开源的大模型&#xff0c;在这之后&#xff0c;很多开源模型都是基于LLaMA的&#xff0c;比如斯坦福大学的羊驼模型。 LLaMA的重点是比…

从Vue层面 - 解析发布订阅模式和观察者模式区别

目录 前言一、发布订阅模式什么是发布订阅模式&#xff1f;应用场景 二、观察者模式1&#xff09;什么是观察者模式&#xff1f;2&#xff09;应用场景3&#xff09;vue中的观察者模式观察者&#xff08;订阅者&#xff09; - Watcher目标者&#xff08;发布者&#xff09; - D…

剑指 Offer 46.! 把数字翻译成字符串(动态规划,青蛙跳台问题的变形)

剑指 Offer 46. 把数字翻译成字符串 中等 588 相关企业 给定一个数字&#xff0c;我们按照如下规则把它翻译为字符串&#xff1a;0 翻译成 “a” &#xff0c;1 翻译成 “b”&#xff0c;……&#xff0c;11 翻译成 “l”&#xff0c;……&#xff0c;25 翻译成 “z”。一个数字…

rtthread的idle线程不应该长时间堵塞

RT-Thread是一个实时嵌入式操作系统&#xff0c;它的空闲线程&#xff08;Idle Thread&#xff09;是在系统中没有其他任务需要执行时运行的线程。空闲线程通常用于执行一些低优先级的任务或者进行系统的休眠等操作。 RT-Thread的空闲线程不能在线程中堵塞的原因是为了确保系统…

STM32CubeIDE(串口)

目录 一、轮询模式 1.1 配置USART2为异步模式 1.2 500ms发送一次消息 1.3 通信结果 1.4 串口控制LED 二、中断收发 2.1 开启中断 2.2 中断发送接收 2.2.1 中断发送只需要调用接口 2.2.2 中断接收 2.3 实验结果 三、DMA模式与收发不定长数据 3.1 DMA通道配置 3.2 DMA…

设计模式-命令模式在Java中的使用示例-桌面程序自定义功能键

场景 欲开发一个桌面版应用程序&#xff0c;该应用程序为用户提供了一系列自定义功能键&#xff0c;用户可以通过这些功能键来实现一些快捷操作。 用户可以将功能键和相应功能绑定在一起&#xff0c;还可以根据需要来修改功能键的设置&#xff0c;而且系统在未来可能还会增加…

使用 OpenCV 进行图像模糊度检测(拉普拉斯方差方法)

写在前面 工作中遇到&#xff0c;简单整理人脸识别中&#xff0c;对于模糊程度较高的图像数据&#xff0c;识别率低&#xff0c;错误率高。虽然使用 AdaFace 模型&#xff0c;对低质量人脸表现尤为突出。但是还是需要对 模糊程度高的图像进行丢弃处理当前通过阈值分类&#xff…

临时段的cleanup引起的enq:TT–content等待事件处理过程

文章目录 1.问题描叙2.查因过程3.根因4.处理过程4.1 Mark目标segment为CORRUPT4.2 Drop目标segment4.3 释放占用的空间 1.问题描叙 接到用户抱怨无法修改表架构&#xff1a; 2.查因过程 查看当前DB活动&#xff1a; Select sid,serial#,osuser,program,terminal,sql_id,bl…

计算机视觉:图像质量评价指标之 PSNR 和 SSIM

1. PSNR (Peak Signal-to-Noise Ratio) 峰值信噪比 由上可见&#xff0c;PSNR相对MSE多了一个峰值&#xff0c;MSE是绝对误差&#xff0c;再加上峰值是一个相对误差指标 一般地&#xff0c;针对 uint8 数据&#xff0c;最大像素值为 255,&#xff1b;针对浮点型数据&#xff…

基于注解手写Spring的IOC(上)

一、思路 先要从当前类出发找到对应包下的所有类文件&#xff0c;再从这些类中筛选出类上有MyComponent注解的类&#xff1b;把它们都装入Map中&#xff0c;同时类属性完成MyValue的赋值操作。 二、具体实现 测试类结构&#xff1a; 测试类&#xff1a;myse、mycontor、BigSt…

2023牛客暑期多校-J-Qu‘est-ce Que C‘est?(DP)

题意&#xff1a; 给定长度为n的数列,要求每个数都在的范围&#xff0c;且任意长度大于等于2的区间和都大于等于0&#xff0c;问方案数。。 思路&#xff1a; 首先要看出是dp题&#xff0c;用来表示遍历到第i位且后缀和最小为x的可行方案数&#xff08;此时的后缀可以只有最…

IT技术面试必备:如何做好IT类技术面试?

博主 默语带您 Go to New World. ✍ 个人主页—— 默语 的博客&#x1f466;&#x1f3fb; 《java 面试题大全》 &#x1f369;惟余辈才疏学浅&#xff0c;临摹之作或有不妥之处&#xff0c;还请读者海涵指正。☕&#x1f36d; 《MYSQL从入门到精通》数据库是开发者必会基础之…

【Linux】多线程的补充

1 线程安全的单例模式 1.1 什么是单例模式 单例模式是一种 "经典的, 常用的, 常考的" 设计模式. 1.2 什么是设计模式 IT行业这么火, 涌入的人很多. 俗话说林子大了啥鸟都有. 大佬和菜鸡们两极分化的越来越严重. 为了让菜鸡们不太拖大佬的后腿, 于是大佬们针对一些…

04-导数判断凹(concave)凸(convex)性_导数用于泰勒展开

导数与函数凹凸性的关系 函数的二阶导数是和函数的凹凸性是有关系的&#xff0c;凹凸性怎么定义的&#xff1f; 先来做简单的回顾&#xff0c;更多的会在最优化方法里面给大家讲&#xff0c;这里先记住凸函数是向下凸的&#xff0c; 反正就是凹的&#xff0c;是否是凸函数可以…

秒级体验本地调试远程 k8s 中的服务

点击上方蓝色字体&#xff0c;选择“设为星标” 回复”云原生“获取基础架构实践 背景 在这个以k8s为云os的时代&#xff0c;程序员在日常的开发过程中&#xff0c;肯定会遇到各种问题&#xff0c;比如&#xff1a;本地开发完&#xff0c;需要部署到远程k8s集群&#xff0c;本地…