隐身之术:深入解析代理模式的神秘力量

一、定义

代理模式(Proxy Pattern)为其他对象提供一种代理以控制对这个对象的访问,属于结构型模式。

二、解决什么问题

主要解决在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。

三、何时使用

想在访问一个类时做一些控制。

四、如何使用

增加中间层

核心思想:
1.提供一个抽象的行为(抽象类或者接口)
2.代理类和被代理对象都实现抽象的行为
3.代理类拥有被代理对象的引用
4.访问代理类

核心角色:

  1. 抽象行为类
  2. 代理类
  3. 被代理对象(具体行为的实现类)
    在这里插入图片描述

五、静态代理

基础版实现

Image接口:

/*** <p>* 图片接口* </p>** @author shiqi* @version 1.0.0* @createTime 2023-12-29*/
public interface Image {/*** 显示方法*/void display();}

具体的RealImage对象

/*** <p>* 具体实现类* </p>** @author shiqi* @version 1.0.0* @createTime 2023-12-29*/
public class RealImage implements Image {private String fileName;public RealImage(String fileName){this.fileName = fileName;loadFromDisk(fileName);}@Overridepublic void display() {System.out.println("Displaying " + fileName);}private void loadFromDisk(String fileName){System.out.println("Loading " + fileName);}
}

代理对象ProxyImage

/*** <p>* 代理类,代理具体的RealImage对象,在访问RealImage对象时,通过代理类处理* </p>** @author shiqi* @version 1.0.0* @createTime 2023-12-29*/
public class ProxyImage implements Image {private RealImage realImage;private String fileName;public ProxyImage(String fileName) {this.fileName = fileName;}@Overridepublic void display() {if(realImage == null){realImage = new RealImage(fileName);}}
}

进阶版实现

在执行目标方法前后执行其他的业务逻辑

代理主题角色类ISubject

/*** <p>* 代理主题角色类* </p>** @author shiqi* @version 1.0.0* @createTime 2023-12-29*/
public interface  ISubject {void request();
}

真实主题角色类RealSubject

/*** <p>* 真实主题角色类* </p>** @author shiqi* @version 1.0.0* @createTime 2023-12-29*/
public class RealSubject implements ISubject{@Overridepublic void request() {System.out.println("real service is called.");}
}

代理主题角色类ProxySubject

/*** <p>* 代理主题角色类* </p>** @author shiqi* @version 1.0.0* @createTime 2023-12-29*/
public class ProxySubject implements ISubject {private ISubject subject;public ProxySubject(ISubject subject) {this.subject = subject;}@Overridepublic void request() {before();subject.request();after();}private void before() {System.out.println("called request before.");}private void after() {System.out.println("called request after.");}}

测试客户端


/*** <p>* 测试客户端* </p>** @author shiqi* @version 1.0.0* @createTime 2023-12-29*/
public class ProxySubjectDemo {public static void main(String[] args) {ISubject subject = new ProxySubject(new RealSubject());subject.request();}
}

运行结果:
在这里插入图片描述

六、动态代理实现

JDK动态代理

我们用一个媒婆例子来实现

  1. 定义一个IPerson接口,提供寻找真爱的方法findLove
public interface IPerson {void findLove();}
  1. 定义具体的媒婆类JdkMeipo
/*** <p>* 具体的媒婆* </p>** @author shiqi* @version 1.0.0* @createTime 2023-10-27*/
public class JdkMeipo implements InvocationHandler {private IPerson target;public IPerson getInstance(IPerson target){this.target = target;Class<?> clazz =  target.getClass();return (IPerson) Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {before();Object result = method.invoke(this.target, args);after();return null;}private void after() {System.out.println("双方同意,开始交往");}private void before() {System.out.println("我是媒婆,已经收集到你的需求,开始物色");}
}
  1. 定义具体的要找对象的Person类
/*** <p>** </p>** @author shiqi* @version 1.0.0* @createTime 2023-10-27*/
public class Zhangsan implements IPerson{@Overridepublic void findLove() {System.out.println("张三要求:肤白貌美大长腿");}
}
  1. 创建客户端进行测试
/*** <p>* 测试客户端* </p>** @author shiqi* @version 1.0.0* @createTime 2023-10-27*/
public class Test {public static void main(String[] args) {JdkMeipo jdkMeipo=new JdkMeipo();Zhangsan zhangsan=(Zhangsan) jdkMeipo.getInstance(new Zhangsan());zhangsan.findLove();}}

运行结果:

在这里插入图片描述

Cglib动态代理

  1. 定义核心的媒婆类CglibMeipo
import java.lang.reflect.Method;/*** <p>* Cglib的媒婆类* </p>** @author shiqi* @version 1.0.0* @createTime 2023-10-27*/
public class CglibMeipo implements MethodInterceptor {private IPerson target;public Object getInstance(Class<?> clazz) throws Exception {//相当于Proxy,代理的工具类Enhancer enhancer = new Enhancer();enhancer.setSuperclass(clazz);enhancer.setCallback(this);return enhancer.create();}@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {before();Object obj = methodProxy.invokeSuper(o, objects);after();return obj;}private void before(){System.out.println("我是媒婆,我要给你找对象,现在已经确认你的需求");System.out.println("开始物色");}private void after(){System.out.println("OK的话,准备办事");}
}
  1. 定义测试客户端 CglibProxyTest
/*** <p>* 测试客户端* </p>** @author shiqi* @version 1.0.0* @createTime 2023-12-29*/
public class CglibProxyTest {public static void main(String[] args) throws Exception {CglibMeipo cglibMeipo = new CglibMeipo();Zhangsan zhangsan = (Zhangsan) cglibMeipo.getInstance(Zhangsan.class);zhangsan.findLove();}
}

Cglib动态代理和Jdk动态代理的区别

CglibProxy和JdkProxy都是Java中用于实现代理模式的两种不同的方式。它们之间的主要区别在于代理的实现方式和对代理目标的要求。

基于继承 vs 基于接口:

CglibProxy使用的是基于继承的代理方式。它通过创建目标类的子类来实现代理。
JdkProxy使用的是基于接口的代理方式。它要求目标类必须实现一个接口,然后通过动态生成实现该接口的代理类。

代理类的生成方式:

CglibProxy通过字节码操作,在运行时动态生成目标类的子类,继承目标类,并重写需要代理的方法。
JdkProxy使用Java的动态代理机制,通过java.lang.reflect.Proxy和InvocationHandler接口来生成代理类,该代理类实现了目标接口,并将方法调用委托给InvocationHandler的实现。

性能:

由于CglibProxy是通过生成目标类的子类,因此在性能上可能会比JdkProxy略慢,尤其是对于目标类的方法调用。
JdkProxy相对来说更轻量,因为它是基于接口的代理,不需要生成子类。

应用场景:

CglibProxy适用于那些没有实现接口的类的代理,因为它是基于继承的。
JdkProxy适用于那些实现了接口的类的代理,且它更符合Java的设计哲学,推崇面向接口编程。

七、代理模式在源码中的体现

  1. ProxyFactoryBean核心方法getObject (),源码如下:
    在这里插入图片描述
  2. Spring AOP
    Spring 利用动态代理实现AOP 时有两个非常重要的类:JdkDynamicAopProxy 类和C g l i b A o p P r o x y 类 ,来 看 一 下类 图 ,如 下 图 所 示 。
    在这里插入图片描述

S p r i n g 中的代理选择原则

  1. 当 Bean有实现接口时 ,Spring就会用Jdk动态代理。
  2. 当Bean没有实现接又时,Spring 会选择CGLib代理。
  3. Spring可 以 通 过 配 置 强 制 使 用 CGLib代 理 ,只 需 在Spring的 配 置 文 件 中 加 入 如 下 代 码 : <aop:aspectj-autoproxy proxy-target-class=“true”/>

八、总结

代理模式的优缺点

优点

  1. 代理模式能将代理对象与真实被调用目标对象分离
  2. 在一定程度上降低了系统的耦合性,扩展性好
  3. 可以起到保护目标对象的作用
  4. 可以增强目标对象的功能 (代理模式核心的点)

缺点

  1. 代理模式会造成系统设计中类的数量增加。
  2. 在客户端和目标对象中增加一个代理对象,会导致请求处理速度变慢
  3. 增加了系统的复杂度

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

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

相关文章

一篇文章深入认识微服务SpringCloud和Dubbo的区别

1、SpringCloud是什么 SpringCloud, 基于SpringBoot提供了一套微服务解决方案&#xff0c;包括服务注册与发现&#xff0c;配置中心&#xff0c;全链路监控&#xff0c;服务网关&#xff0c;负载均衡&#xff0c;熔断器等组件&#xff0c;除了基于NetFlix的开源组件做高度抽象…

Conda:Python环境管理的瑞士军刀

在数据科学和机器学习的世界中&#xff0c;管理各种库和依赖关系的重要性不容忽视。Conda 就是为此而生的强大工具。本文将深入探讨 Conda 的简介、功能以及使用示例&#xff0c;帮助你更好地理解和使用这个工具。 Conda 简介 Conda 是一个开源的包管理系统和环境管理系统&am…

新品出击 | 软网关BLIoTLink免费发布

新品出击|软网关BLIoTLink免费发布 BLIoTLink是一款免费的物联网协议转换软件&#xff0c;可以部署在任何基于Linux OS的系统&#xff08;Linux、Debian、Ubuntu、FreeRTOS、RT-Thread&#xff09;中&#xff0c;使用灵活&#xff0c;可以实现数据的采集以及接入网络平台。 BL…

0开始配置Cartographer建图和导航定位

0开始配置Cartographer 日期&#xff1a;12-19 硬件&#xff1a;激光雷达IMU 小车的tf变换&#xff1a; 建图配置 lua文件配置&#xff1a;my_robot.lua include "map_builder.lua" include "trajectory_builder.lua"options {map_builder MAP_BUILDE…

HarmonyOS page生命周期函数讲解

下面 我们又要看一个比较重要的点了 页面生命周期 页面组件有三个生命周期 onPageShow 页面显示时触发 onPageHide 页面隐藏时触发 onBackPress 页面返回时触发 这里 我们准备两个组件 首先是 index.ets 参考代码如下 import router from ohos.router Entry Component struc…

Python FastApi连接oracle进行查询

这边技术选型是cx_oracle进行连接查询&#xff0c;cx_oracle的使用首先要有官方的客户端才能连接到数据库&#xff0c;python并不自带客户端。我用是Python3.9 安装客户端 可以到官网在选择最新版进行下载。 Instant Client for Microsoft Windows (x64) 64-bit 或者直接从我…

HBase深度历险 | 京东物流技术团队

简介 HBase 的全称是 Hadoop Database&#xff0c;是一个分布式的&#xff0c;可扩展&#xff0c;面向列簇的数据库&#xff0c;是一个通过大量廉价的机器解决海量数据的高速存储和读取的分布式数据库解决方案。本文会像剥洋葱一样&#xff0c;层层剥开她的心。 特点 首先我…

【机器学习】深度学习概论(二)

五、受限玻尔兹曼机&#xff08;Restricted Boltzmann Machine&#xff0c;RBM&#xff09; 5.1 RBM介绍 示例代码&#xff1a; Python 编写了一个简单的 RBM 实现&#xff0c;并用一些假数据训练了它。然后&#xff0c;他展示了如何用 RBM 来解释用户的电影偏好&#xff0c;以…

MySQL MVCC精讲

版本链 我们前面说过&#xff0c;对于使用InnoDB存储引擎的表来说&#xff0c;它的聚簇索引记录中都包含两个必要的隐藏列&#xff08;row_id并不是必要的&#xff0c;我们创建的表中有主键或者非NULL的UNIQUE键时都不会包含row_id列&#xff09;&#xff1a; trx_id&#xff…

[ 云计算 | AWS ] 对比分析:Amazon SNS 与 SQS 消息服务的异同与选择

文章目录 一、前言二、Amazon SNS 服务&#xff08;Amazon Simple Notification Service&#xff09;三、Amazon SQS 服务&#xff08;Amazon Simple Queue Service&#xff09;四、SNS 与 SQS 的区别&#xff08;本文重点&#xff09;4.1 基于推送和轮询区别4.2 消费者数量对应…

Hadoop之Yarn 详细教程

1、yarn 的基本介绍和产生背景 YARN 是 Hadoop2 引入的通用的资源管理和任务调度的平台&#xff0c;可以在 YARN 上运行 MapReduce、Tez、Spark 等多种计算框架&#xff0c;只要计算框架实现了 YARN 所定义的 接口&#xff0c;都可以运行在这套通用的 Hadoop 资源管理和任务调…

[足式机器人]Part4 南科大高等机器人控制课 CH12 Robotic Motion Control

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;CLEAR_LAB 笔者带更新-运动学 课程主讲教师&#xff1a; Prof. Wei Zhang 课程链接 &#xff1a; https://www.wzhanglab.site/teaching/mee-5114-advanced-control-for-robotics/ 南科大高等机器人控制课 Ch12 Robotic …

uni-appcss语法

锋哥原创的uni-app视频教程&#xff1a; 2023版uniapp从入门到上天视频教程(Java后端无废话版)&#xff0c;火爆更新中..._哔哩哔哩_bilibili2023版uniapp从入门到上天视频教程(Java后端无废话版)&#xff0c;火爆更新中...共计23条视频&#xff0c;包括&#xff1a;第1讲 uni…

PPT录制视频的方法,轻松提升演示效果!

在现代工作和学习中&#xff0c;ppt是一种常见的演示工具&#xff0c;而将ppt转化为视频形式更能方便分享和传播。本文将介绍两种ppt录制视频的方法&#xff0c;每一种方法都将有详细的步骤和简要的介绍&#xff0c;通过这些方法&#xff0c;你可以轻松将ppt制作成视频&#xf…

秋招复习篇之代码规范

目录 前言 1、变量命名 2、代码空格 1&#xff09;操作符左右一定有空格&#xff0c; 2&#xff09;分隔符&#xff08;, 和;&#xff09;前一位没有空格&#xff0c;后一位保持空格&#xff0c;例如&#xff1a; 3&#xff09;大括号和函数保持同一行&#xff0c;并有一个空格…

双语!性能优越|融合黏菌和差分变异的量子哈里斯鹰算法SDMQHHO

前面的文章里卡卡介绍了哈里斯鹰优化算法(Harris Hawks Optimization, HHO).HHO是 Heidari等[1]于2019年提出的一种新型元启发式算法&#xff0c;设计灵感来源于哈里斯鹰在捕食猎物过程中的合作行为以及突然袭击的狩猎风格&#xff0c;具有需调参数少、原理简单易实现、局部搜索…

4.20 构建onnx结构模型-Reduce

前言 构建onnx方式通常有两种&#xff1a; 1、通过代码转换成onnx结构&#xff0c;比如pytorch —> onnx 2、通过onnx 自定义结点&#xff0c;图&#xff0c;生成onnx结构 本文主要是简单学习和使用两种不同onnx结构&#xff0c; 下面以 Reduce 结点进行分析 方式 方法…

002文章解读与程序——中国电机工程学报EI\CSCD\北大核心《计及源荷不确定性的综合能源生产单元运行调度与容量配置两阶段随机优化》已提供下载资源

&#x1f446;&#x1f446;&#x1f446;&#x1f446;&#x1f446;&#x1f446;&#x1f446;&#x1f446;&#x1f446;&#x1f446;&#x1f446;&#x1f446;&#x1f446;&#x1f446;&#x1f446;&#x1f446;&#x1f446;&#x1f446;下载资源链接&#x1f4…

Java——猫猫图鉴微信小程序(前后端分离版)

目录 一、开源项目 二、项目来源 三、使用框架 四、小程序功能 1、用户功能 2、管理员功能 五、使用docker快速部署 六、更新信息 审核说明 一、开源项目 猫咪信息点-ruoyi-cat: 1、一直想做点项目进行学习与练手&#xff0c;所以做了一个对自己来说可以完成的…

【Linux系统化学习】进程终止的奥秘

个人主页点击直达&#xff1a;小白不是程序媛 Linux专栏&#xff1a;Liunx系统化学习 代码仓库&#xff1a;Gitee 目录 获取函数返回值 退出码 进程退出的场景 错误码 信号终止异常代码 进程的终止 main函数直接return exit函数 _exit函数 获取函数返回值 在C语言学…