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

news2025/4/13 12:32:50

一、定义

代理模式(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);
    }


    @Override
    public 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;
    }
    
    @Override
    public 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{
    @Override
    public 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;
    }
    
    @Override
    public 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);
    }

    @Override
    public 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{
    @Override
    public 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();
    }

    @Override
    public 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.coloradmin.cn/o/1344218.html

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

相关文章

Python中matplotlib库的使用1

1 matplotlib库简介 matplotlib是一个数学绘图库&#xff0c;可以将数据通过图形的方式显示出来&#xff0c;也就是数据可视化。 2 matplotlib库的安装 2.1 打开cmd窗口 点击键盘的“Win”“R”键&#xff0c;在弹出的“运行”对话框的“打开”栏中输入“cmd”&#xff0c;…

OCR在审核应用落地

本文字数&#xff1a;6686字 预计阅读时间&#xff1a;35分钟 01 背景 1、业务背景 在传统视频审核场景中&#xff0c;审核人员需要对进审视频中的文字内容进行逐一审核&#xff0c;避免在文字上出现敏感词、违禁词或者广告等相关词汇。这种人工审核费时费力&#xff0c;并且由…

听GPT 讲Rust源代码--src/tools(36)

File: rust/src/tools/clippy/clippy_lints/src/loops/empty_loop.rs 在Rust源代码中&#xff0c;empty_loop.rs文件位于src/tools/clippy/clippy_lints/src/loops/目录下&#xff0c;它的作用是实现并提供一个名为EMPTY_LOOP的Lint规则。Clippy是一个Rust的静态分析工具&#…

RS®FSW 信号与频谱分析仪

R&SFSW 信号与频谱分析仪 简述&#xff1a; R&SFSW 信号与频谱分析仪高性能 R&SFSW 信号与频谱分析仪可用于完成严苛任务。它具备较高的内部分析带宽&#xff0c;可对宽带组件和通信系统进行特征校准。分析仪具备出色的相位噪声&#xff0c;有助于开发适用于雷达…

关于Citrix NetScaler ADC 和网关设备受到攻击的动态情报

一、基本内容 据美国网络安全和基础设施安全局CISA的公告&#xff0c;最新披露的Citrix NetScaler应用交付控制器&#xff08;ADC&#xff09;和网关设备中存在关键的安全漏洞&#xff0c;已被攻击者滥用。这些漏洞使得攻击者能够在易受攻击的系统上投放Web shell&#xff0c;…

揭秘营销返利模式!

随着互联网的普及和发展&#xff0c;越来越多的商家开始采用营销返利模式来吸引消费者。这种模式不仅可以提高销售额&#xff0c;还可以让消费者获得实实在在的优惠。本文将详细解析营销返利模式的秘密&#xff0c;让你轻松掌握这一有效的营销策略&#xff01; 一、什么是营销返…

java美容管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java Web美容管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0&…

多维时序 | Matlab实现PSO-GCNN粒子群优化分组卷积神经网络多变量时间序列预测

多维时序 | Matlab实现PSO-GCNN粒子群优化分组卷积神经网络多变量时间序列预测 目录 多维时序 | Matlab实现PSO-GCNN粒子群优化分组卷积神经网络多变量时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 Matlab实现PSO-GCNN粒子群优化分组卷积神经网络多…

详解FreeRTOS:FreeRTOSConfig.h系统配置文件(拓展篇—1)

目录 1、“INCLUDE_”宏 2、“config”宏 实际使用FreeRTOS的时候,时常需要根据自己需求来配置 FreeRTOS,不同架构的MCU,配置也不同。 FreeRTOS的系统配置文件为FreeRTOSConfig.h,在配置文件中可以完成FreeRTOS的裁剪和配置,这是非常重要的一个文件,本篇博文就来讲解这…

GO学习记录 —— 创建一个GO项目

文章目录 前言一、项目介绍二、目录介绍三、创建过程1.引入Gin框架、创建main2.加载配置文件3.连接MySQL、redis4.创建结构体5.错误处理、返回响应处理 前言 代码地址 下载地址&#xff1a;https://github.com/Lee-ZiMu/Golang-Init.git 一、项目介绍 1、使用Gin框架来创建项…

SVN下载安装(服务器与客户端)

1.下载 服务器下载&#xff1a;Download | VisualSVN Server 客户端下载&#xff1a;自行查找 2. 服务器安装 双击执行 运行 下一步 同意下一步 下一步 选中安装目录 3. 客户端安装 双击执行 下一步 4. 服务器创建仓库 5. 服务器创建用户 6. 客户端获取资源 文件夹右键

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

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

传统项目基于tomcat cookie单体会话升级分布式会话解决方案

传统捞项目基于servlet容器 cookie单体会话改造分布式会话方案 ##引入redis,spring-session依赖 <!--redis依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>&…

将网页变身移动应用:网址封装成App的完全指南

什么是网址封装&#xff1f; 网址封装是一个将你的网站或网页直接嵌入到一个原生应用容器中的过程。用户可以通过下载你的App来访问网站&#xff0c;而无需通过浏览器。这种方式不仅提升了用户体验&#xff0c;还可利用移动设备的功能&#xff0c;如推送通知和硬件集成。 小猪…

权威Scrum敏捷开发企业培训分享

课程简介 Scrum是目前运用最为广泛的敏捷开发方法&#xff0c;是一个轻量级的项目管理和产品研发管理框架。 这是一个两天的实训课程&#xff0c;面向研发管理者、项目经理、产品经理、研发团队等&#xff0c;旨在帮助学员全面系统地学习Scrum和敏捷开发, 帮助企业快速启动敏…

【HarmonyOS】鸿蒙开发简介与项目基础配置演示

从今天开始&#xff0c;博主将开设一门新的专栏用来讲解市面上比较热门的技术 “鸿蒙开发”&#xff0c;对于刚接触这项技术的小伙伴在学习鸿蒙开发之前&#xff0c;有必要先了解一下鸿蒙&#xff0c;从你的角度来讲&#xff0c;你认为什么是鸿蒙呢&#xff1f;它出现的意义又是…

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

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

大数据学习(30)-Spark Shuffle

&&大数据学习&& &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 承认自己的无知&#xff0c;乃是开启智慧的大门 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4dd;支持一下博主哦&#x1f91…

添加 Android App Links

添加 Android App Links功能 介绍一个简单的效果Android配置Add Url intent filtersAdd logic to handle the intentAssociate website 搭建网页支持AppLinks 介绍 Android App Links 是指将用户直接转到 Android 应用内特定内容的 HTTP 网址。Android App Links 可为您的应用带…

【深度学习-图像分类】02 - AlexNet 论文学习与总结

论文地址&#xff1a;ImageNet Classification with Deep Convolutional Neural Networks 论文学习 1. 摘要 本研究训练了一个大型深度卷积神经网络&#xff08;CNN&#xff09;&#xff0c;用于对ImageNet LSVRC-2010比赛中的1.2百万高分辨率图像进行分类&#xff0c;这些图…