【了解一下静态代理与动态代理】

news2024/10/28 1:12:38

文章目录

    • 一.什么是静态代理与动态代理
    • 二.静态代理
    • 三.动态代理
      • 1.jdk动态代理
      • 2.cglib动态代理
    • 四.小结

一.什么是静态代理与动态代理

什么是代理?代理是一种设计模式,在这种模式中,一个类(代理类)代表另一个类(目标类)进行操作。代理类控制对目标类的访问,并可能添加额外的功能,如权限检查、日志记录、延迟加载、缓存、事务处理等。

  1. 静态代理
  • 定义:静态代理是在编译时创建的代理类,由开发者手动定义代理类,不会随着程序运行时的条件改变而变化,适用于在类的行为不变的情况下,可以增加一些额外的功能。
  • 特点:
    1.代理类在编译阶段就已经存在。
    2.代理类需要实现与目标类相同的接口,并在接口方法中调用目标类的相应方法。
    3.代码量较多,需手动编写代理类,增加了开发成本。
  • 优点:实现简单,直接创建代理类即可。
  • 缺点:每个类都需要一个代理类,导致代码冗余,难以维护。不适合大量类的代理需求。
  1. 动态代理
  • 定义:代理类在运行时动态生成,通常使用反射机制或第三方库(如JDK动态代理、CGLIB)。动态代理允许在运行时改变代理行为,通常更灵活。
  • 特点:
    1.不需要为每个代理类手动创建代理类,而是通过反射在运行时动态创建代理对象。
    2.代理类可以处理实现多个接口的目标类。
  • 优点:可以复用代理逻辑,减少代码冗余。适合需要代理多个类或方法的场景。
  • 缺点:
    1.需要通过反射实现,性能相对较低。
    2.仅适用于接口的代理,若目标类未实现接口,需要使用CGLIB等第三方库来实现。

在这里插入图片描述
静态代理需要手动创建代理类,适用于简单、固定的代理需求。动态代理通过反射在运行时动态生成代理对象,适合复杂和可复用的代理需求,灵活性更高。

我们可以把静态代理和动态代理的概念映射到租房的场景中,分别对比“找固定的中介租房”和“通过中介平台动态分配中介租房”这两种情况。

二.静态代理

在静态代理中,我们找了一个中介A来帮忙找房子。中介A提供了一系列的服务,比如筛选房源、安排看房、签约等。这个中介的流程是固定的,我们每次找中介A租房的时候,中介A都按照它们规定的流程执行。

1.类比说明:

  • 我们(Renters,租房者):客户,想要租到合适的房子。
  • 房东(Landlord,真实的出租者):拥有房源,真实的目标对象。
  • 中介A(LandlordProxy):静态代理角色,由于我们每次都找同一家中介,这家中介在编译时就明确了自己的代理流程,不会临时调整。

2.静态代理流程:

  1. 我们找到固定的中介A,希望租房。
  2. 中介A开始按固定流程代理我们完成租房:筛选房源、安排带看、签合同等。
  3. 我们通过中介A租到了房子。

3.静态代理的缺点:
如果我们之后需要不同的服务,比如希望找到不收中介费的中介B,又或者找专门提供短租的中介C,那我们就得找不同的中介,并为每个中介创建单独的代理对象,增加了复杂度,不够灵活。

对上述场景用静态代理代码实现:
假设有一个房东类和一个中介代理类,静态代理需要手动创建代理类来完成租房的代理服务。

public interface Rent {
    // 定义租房接口
    void rentHouse();
}

/**
 * 房东A(真实的出租者),实现租房接口
 */
public class LandlordA implements Rent {
    @Override
    public void rentHouse() {
        System.out.println("房东A待出租的房子");
    }
}

/**
 * 中介A
 */
public class LandlordAProxy implements Rent {

    // 中介有房东信息
    private final LandlordA landlordA = new LandlordA();

    @Override
    public void rentHouse() {
        System.out.println("中介带租客看房源信息");

        // 调用房东的租房方法
        landlordA.rentHouse();

        System.out.println("中介带我们跟房东处理租赁合同");
    }
}

/**
 * 我们(打工人):租房者
 */
public class Renters {

    public static void main(String[] args) {

            System.out.println("我是租客,找到中介..");

            // 创建代理
            LandlordProxy agency = new LandlordProxy();

            // 通过代理租房
            agency.rentHouse();
    }
}

输出结果:

  • 我是租客,找到中介…
  • 中介带租客看房源信息
  • 房东A待出租的房子
  • 中介带我们跟房东处理租赁合同

缺点就是我想换中介了,又得写一套静态代理逻辑,代码量大。

三.动态代理

在动态代理中,我们没有选择某一个固定的中介,而是通过一个中介平台下单。这个中介平台可以根据我们的需求,自动匹配一个合适的中介来帮忙租房。我们只需告诉平台需求,平台会动态地分配一个代理人,而我们并不关心具体是哪个中介代理的,只关注服务结果。

1.类比说明:

  • 我们(Renters,租房者):客户,目标是找到合适的房源。
  • 房东(Landlord,真实的出租者):拥有房源,真实的目标对象。
  • 中介平台(JdkDynamicProxyPlatform/CglibDynamicProxyPlatform):动态代理角色,平台会根据需求实时生成合适的代理人。

2.动态代理流程:

  1. 我们将租房需求提交到中介平台,平台在运行时根据需求生成适合的代理人。
  2. 代理人动态匹配房源、安排看房和签约等代理流程。
  3. 我们通过中介平台成功租到合适的房子。

3.动态代理的优点
动态代理可以根据需求灵活匹配代理流程,比如选择是否提供带看服务、是否收取中介费等,无需手动创建代理类。这种方式适合租房需求多变的场景。

动态代理又分为jdk动态代理、cglib动态代理

1.jdk动态代理

JDK代理,也称为基于接口的动态代理,是Java动态代理的一种实现方式,它要求被代理的对象必须实现一个或多个接口。JDK代理主要利用了java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口来生成代理对象。
当你通过JDK代理创建代理对象时,你需要提供一个实现了InvocationHandler接口的类,该类中的invoke方法会拦截并处理所有通过代理对象调用的方法。Proxy类则负责生成代理类的实例。

/**
 * JDK动态代理租房平台
 */
public class JdkDynamicProxyPlatform implements InvocationHandler {

    // 中介有房东信息
    private final LandlordA target = new LandlordA();

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("中介带租客看房源信息");

        // 调用房东的租房方法
        Object result = method.invoke(target, args);

        System.out.println("中介带我们跟房东处理租赁合同");

        return result;
    }

    /**
     * 定义获取代理对象方法
     */
    public Object getLandlordProxy(){
        //JDK动态代理只能针对实现了接口的类进行代理,newProxyInstance函数所需参数就可看出
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }
}

/**
 * 我们(打工人):租房者
 */
public class Renters {

    public static void main(String[] args) {

            System.out.println("我是租客,找到JdkDynamicProxyPlatform中介平台..");

            // 动态生成代理对象
            Rent agency = (Rent)new JdkDynamicProxyPlatform().getLandlordProxy();

            // 通过动态代理租房
            agency.rentHouse();
    }
}

输出结果:

  • 我是租客,找到JdkDynamicProxyPlatform中介平台…
  • 中介带租客看房源信息
  • 房东A待出租的房子
  • 中介带我们跟房东处理租赁合同

2.cglib动态代理

CGLIB(Code Generation Library)动态代理的原理是基于字节码生成,通过创建目标类的子类()来实现代理。它使用ASM(一个操作字节码的框架)在运行时动态生成子类字节码,从而实现对方法的拦截和增强。
CGLIB通过Enhancer类生成目标类的子类,目标类的方法会被重写,代理逻辑插入在调用前后。

/**
 * 房东B(不实现接口的目标类)
 */
public class LandlordB {
    public void rentHouse() {
        System.out.println("房东B待出租的房子");
    }
}

/**
 * Cglib动态代理租房平台
 */
public class CglibDynamicProxyPlatform implements MethodInterceptor {
    // 创建代理对象的方法
    public Object getLandlordProxy() {
        Enhancer enhancer = new Enhancer();
        // 设置代理类的父类
        enhancer.setSuperclass(LandlordB.class);
        // 设置回调函数
        enhancer.setCallback(this);
        // 创建代理对象
        return enhancer.create();
    }

    /**
     * 拦截方法,加入代理逻辑
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("中介带租客看房源信息");
        // 调用目标类的方法
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("中介带我们跟房东处理租赁合同");
        return result;
    }
}

/**
 * 我们(打工人):租房者
 */
public class Renters {
    public static void main(String[] args) {
            System.out.println("我是租客,找到CglibDynamicProxyPlatform中介平台..");
            // 动态生成代理对象
            LandlordB landlordBAgency = (LandlordB) new CglibDynamicProxyPlatform().getLandlordProxy();
            // 通过动态代理租房
            landlordBAgency.rentHouse();
    }
}

输出结果:

  • 我是租客,找到CglibDynamicProxyPlatform中介平台…
  • 中介带租客看房源信息
  • 房东B待出租的房子
  • 中介带我们跟房东处理租赁合同

总结:
JDK动态代理只能代理实现了接口的类,生成的代理对象类型是接口类型。CGLIB代理可以代理任何类,包括没有实现接口的类。生成的代理对象类型是目标类的子类类型。

四.小结

主要介绍下静态代理、jdk动态代理、cglib动态代理,上一篇文章讲Spring声明式事务聊了很多cglib动态代理,做下补充jdk动态代理和静态代理。

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

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

相关文章

【ArcGIS Pro实操第8期】绘制WRF三层嵌套区域

【ArcGIS Pro实操第8期】绘制WRF三层嵌套区域 数据准备ArcGIS Pro绘制WRF三层嵌套区域Map-绘制三层嵌套区域更改ArcMap地图的默认显示方向指定数据框范围 Map绘制研究区Layout-布局出图 参考 本博客基于ArcGIS Pro绘制WRF三层嵌套区域,具体实现图形参考下图&#xf…

cloak斗篷伪装下的独立站

随着互联网的不断进步,越来越多的跨境电商卖家开始认识到独立站的重要性,并纷纷建立自己的独立站点。对于那些有志于进入这一领域的卖家来说,独立站是什么呢?独立站是指个人或小型团队自行搭建和运营的网站。 独立站能够帮助跨境…

C++ 模板编程:解锁高效编程的神秘密码

快来参与讨论💬,点赞👍、收藏⭐、分享📤,共创活力社区。 目录 💯前言 💯泛型编程 💯函数模板 1.函数模板概念 2.函数模板格式 3.函数模板的原理 4.函数模板的实例化 5.模板参…

如何使用DBeaver连接flink

通过DBeaver配置并连接flink: 1. 打开Dbeaver,选择“数据库”--》“数据库驱动管理器” 2.在驱动管理器界面点击新建按钮 3.在新建弹窗输入flink相关的驱动信息,主要包括: org.apache.flink.table.jdbc.FlinkDriver jdbc:flink…

Spring+ActiveMQ

1. 环境搭建 1.1 env-version JDK 1.8 Spring 2.7.13 Maven 3.6 ActiveMQ 5.15.2 1.2 docker-compose.yml version: 3.8services:activemq:image: rmohr/activemq:5.16.3container_name: activemqports:- "61616:61616"- "8161:8161"environment…

图解:什么是多租户?

大家好,我是汤师爷~ 什么是多租户? 多租户是SaaS(软件即服务)领域里特有的一个概念。在SaaS服务中,“租户”指的就是使用这个SaaS系统的客户。 那么租户和用户有什么区别呢?举个例子。假设你正在使用一款…

SQL实战训练之,力扣:1532最近的三笔订单

目录 一、力扣原题链接 二、题目描述 三、建表语句 四、题目分析 五、SQL解答 六、最终答案 七、验证 八、知识点 一、力扣原题链接 1532. 最近的三笔订单 二、题目描述 客户表:Customers ------------------------ | Column Name | Type | --------…

【C++单调栈 贡献法】907. 子数组的最小值之和|1975

本文涉及的基础知识点 C单调栈 LeetCode907. 子数组的最小值之和 给定一个整数数组 arr,找到 min(b) 的总和,其中 b 的范围为 arr 的每个(连续)子数组。 由于答案可能很大,因此 返回答案模 109 7 。 示例 1&#x…

ArcGIS计算多个面要素范围内栅格数据各数值的面积

本文介绍在ArcMap软件中,基于面积制表工具(也就是Tabulate Area工具),基于1个面要素数据集与1个栅格数据,计算每一个面要素中各栅格数据分布面积的方法。 首先,来看一下本文的需求。现有一个矢量面的要素集…

动态规划 —— 斐波那契数列模型-解码方法

1. 解码方法 题目链接: 91. 解码方法 - 力扣(LeetCode)https://leetcode.cn/problems/decode-ways/description/ 2. 题目解析 1. 对字母A - Z进行编码1-26 2. 11106可以解码为1-1-10-6或者11-10-6, 但是11-1-06不能解码 3. 0n不能解码 4. …

springboot项目测试环境构建出的依赖包比本地构建出的依赖包多

本地能够正常启动服务,但是测试环境启动报错。 上述druid是服务pom文件中之前引入的依赖包,后续由于某种原因而不需要该依赖包了,故已在pom文件中移除掉了该依赖包。 移除该依赖包之后,本地服务可正常构建和启动。 而测试环境却…

C语言 | Leetcode C语言题解之第504题七进制数

题目&#xff1a; 题解&#xff1a; char * convertToBase7(int num){if (num 0) {return "0";}bool negative num < 0;num abs(num);char * digits (char *)malloc(sizeof(char) * 32);int pos 0;while (num > 0) {digits[pos] num % 7 0;num / 7;}if…

cm211-1刷机教程镜像包

cm211-1刷机教程 包含镜像包酷看桌面 s905l3-l3b通用 镜像包&#xff1a;https://www.123684.com/s/WGAwjv-5tlv3 1.刷机教程 镜像为线刷镜像包&#xff0c;需要短接刷机 短接刷机&#xff0c;导入镜像包 开始即可。到100%就证明可以了。

四期书生大模型实战营(【入门岛】- 第4关 | 玩转HF/魔搭/魔乐社区)

文章目录 1. 任务介绍闯关任务 2. 平台介绍2.1. HF 平台2.1.1. HF的Transformers库介绍 2.2. GitHub CodeSpaces 和 Hugging Face Spaces 介绍。2.2.1. GitHub CodeSpaces2.2.2. Hugging Face Spaces2.2.3. 总结 3. 模型下载3.1. GitHub CodeSpaces使用3.1.下载internlm2_5-7b-…

MySQL任意版本安装卸载和数据库原理图绘制

MYSQL任意版本安装和卸载 安装&#xff1a; 1、解压文件 --- 不能出现中文路径 2、在解压目录&#xff08;安装目录&#xff09;下&#xff1a; 1>.创建data文件夹 2>.创建配置文件my.txt 然后修改成ini格式 3、修改配置文件 basedirD:\\mysql\\mysql-5.7.28-winx64…

006:看图软件ACDSeePhotoStudio2019安装教程

摘要&#xff1a;本文主要介绍看图软件ACDSee Photo Studio2019的安装流程。 一、软件概述 ACDSee Photo Studio是ACDSee公司开发的一款面向摄影师和图像编辑者的专业软件。它提供了全面的图像处理、管理和发布功能&#xff0c;帮助用户高效地浏览、编辑、分类和分享数字照片。…

新160个crackme - 084-slayer_crackme1

运行分析 点击check&#xff0c;提示注册失败 PE分析 ASM程序&#xff0c;32位&#xff0c;无壳 静态分析&动态调试 ida搜索到关键字符串发现注册文件reg.key 通过动态调试&#xff0c;获得计算机名称为’CONCEALBEAR’通过计算得到int_2 接下来有一个剪贴板判断&#xff0…

从“摸黑”到“透视”:AORO A23热成像防爆手机如何改变工业检测?

在工业检测领域&#xff0c;传统的检测手段常因效率低下、精度不足和潜在的安全风险而受到诟病。随着科技的不断进步&#xff0c;一种新兴的检测技术——红外热成像技术&#xff0c;正逐渐在该领域崭露头角。近期&#xff0c;小编对一款集成红外热成像技术的AORO A23防爆手机进…

【Linux系统】Ubuntu的简单操作

什么是 Ubuntu&#xff1f; Ubuntu&#xff08;乌帮图&#xff09;是一个非洲词汇&#xff0c;它的意思是“人性对待他人”或“群在故我在”。Ubuntu发行版将Ubuntu精神带到软件世界之中。 目前已有大量各种各样基于GNU/Linux的操作系统&#xff0c;例如:Debian,SuSE,Gentoo,R…

【热门主题】000010 深入 Vue.js 组件开发

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【热…