深入解析代理模式:静态代理与动态代理的比较及JDK与CGLIB动态代理技术

1. 静态代理与动态代理的区别

静态代理和动态代理都是实现代理模式的方式,它们在实现上有很大的不同。下面是它们的主要区别:

实现方式不同

静态代理

静态代理是在编译期就已经确定代理对象的类型。代理类需要手动编写,并实现被代理类的接口。

动态代理

动态代理是在运行时动态生成代理对象,代理类不需要手动编写,而是由框架自动生成。Java中的动态代理通常使用Proxy类和InvocationHandler接口实现。

适用范围不同

静态代理

静态代理只适用于代理对象类型固定、接口较少的情况下。每增加一个被代理的接口,就需要编写一个新的代理类。

动态代理

动态代理可以代理任意的接口,无需编写新的代理类,因此更加灵活。适用于代理对象类型不固定、接口较多、灵活性要求较高的情况。

性能表现不同

静态代理

由于静态代理在编译期就已经确定代理对象的类型,因此在运行时执行效率较高。

动态代理

动态代理在运行时需要进行额外的代理对象生成、方法调用转发等操作,因此会存在一定的性能损失。

动态代理的类生成过程

Java虚拟机类加载过程主要分为五个阶段:加载、验证、准备、解析、初始化。

加载阶段

加载阶段需要完成以下三件事情:

  1. 通过一个类的全限定名来获取定义此类的二进制字节流。
  2. 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
  3. 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据访问入口。
    在这里插入图片描述

获取类的二进制字节流的方法

  1. 从本地获取:Java虚拟机可以从本地文件系统加载类的字节码文件。
  2. 从网络中获取:Java虚拟机也可以从网络中加载类的字节码数据。使用类加载器的getResourceAsStream()方法,通过指定URL的方式来获取InputStream,然后通过读取InputStream获取字节码数据。
  3. 运行时计算生成:这种场景使用最多的是动态代理技术,在java.lang.reflect.Proxy类中,就是用了ProxyGenerator.generateProxyClass来为特定接口生成形式为*$Proxy的代理类的二进制字节流。
    在这里插入图片描述

总结

  • 静态代理适用于代理对象类型固定、接口较少、性能要求较高的情况。
  • 动态代理适用于代理对象类型不固定、接口较多、灵活性要求较高的情况。

通过动态代理,可以根据接口或目标对象,计算出代理类的字节码,然后再加载到JVM中使用,使得代理对象的生成和方法调用更加灵活和动态。

JDK动态代理和CGLIB动态代理是Java语言中实现动态代理的两种方式。它们之间的主要区别如下:

2. JDK动态代理与CGLIB动态代理的区别?

基于的技术不同

  1. JDK动态代理:基于Java的反射机制实现。使用java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口来创建动态代理类。
  2. CGLIB动态代理:基于字节码生成技术实现。使用CGLIB库生成代理类,通过操作字节码来生成代理类的子类。

被代理类的要求不同

  1. JDK动态代理:只能代理实现了接口的类。代理类必须实现被代理类的所有接口。
  2. CGLIB动态代理:可以代理没有实现接口的类。代理类通过继承被代理类来生成代理对象。

代理性能不同

  1. JDK动态代理:生成的代理类性能相对较低,因为它是基于反射实现的,每次方法调用都需要通过反射机制来处理。
  2. CGLIB动态代理:生成的代理类性能相对较高,因为它是基于字节码生成技术实现的,直接生成字节码来处理方法调用。

代理方式不同

  1. JDK动态代理:基于接口实现的代理方式。代理类必须实现被代理类的所有接口。
  2. CGLIB动态代理:基于继承实现的代理方式。代理类通过继承被代理类来生成代理对象。

选择依据

  • 如果被代理类实现了接口,优先选择JDK动态代理。
  • 如果被代理类没有实现接口,只能使用CGLIB动态代理。

JDK动态代理示例

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public interface Subject {
    void request();
}

public class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("Real subject request.");
    }
}

public class ProxyHandler implements InvocationHandler {
    private Object realSubject;

    public ProxyHandler(Object realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        preRequest();
        Object result = method.invoke(realSubject, args);
        postRequest();
        return result;
    }

    private void preRequest() {
        System.out.println("Pre request processing.");
    }

    private void postRequest() {
        System.out.println("Post request processing.");
    }
}

public class Client {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        Subject proxy = (Subject) Proxy.newProxyInstance(
                realSubject.getClass().getClassLoader(),
                realSubject.getClass().getInterfaces(),
                new ProxyHandler(realSubject)
        );
        proxy.request();
    }
}

CGLIB动态代理示例

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class RealSubject {
    public void request() {
        System.out.println("Real subject request.");
    }
}

public class ProxyInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        preRequest();
        Object result = proxy.invokeSuper(obj, args);
        postRequest();
        return result;
    }

    private void preRequest() {
        System.out.println("Pre request processing.");
    }

    private void postRequest() {
        System.out.println("Post request processing.");
    }
}

public class Client {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(RealSubject.class);
        enhancer.setCallback(new ProxyInterceptor());

        RealSubject proxy = (RealSubject) enhancer.create();
        proxy.request();
    }
}

底层实现

JDK动态代理

JDK生成代理对象依赖的是反射。动态代理类对象继承了Proxy类,并且实现了被代理的所有接口。
在这里插入图片描述

CGLIB动态代理

CGLIB(Code Generation Library)是一个第三方代码生成类库,运行时在内存中动态生成一个子类对象从而实现对目标对象功能的扩展。CGLIB基于ASM字节码工具操作字节码(即动态生成代理,对方法进行增强)。Spring AOP(面向切面编程)基于CGLIB进行封装,实现CGLIB方式的动态代理。
在这里插入图片描述

总结

  • JDK动态代理:适用于代理接口方法,性能稍低,使用反射机制。
  • CGLIB动态代理:适用于代理普通类方法,性能较高,使用字节码生成技术。如果被代理类实现了接口,优先选择JDK动态代理;如果被代理类没有实现接口,那么只能使用CGLIB动态代理。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++20中的基于范围的for循环(range-based for loop)

C11中引入了对基于范围的for循环(range-based for loop)的支持&#xff1a;该循环对一系列值(例如容器中的所有元素)进行操作。代码段如下&#xff1a; const std::vector<int> vec{ 1,2,3,4,5 }; for (const auto& i : vec)std::cout << i << ", …

免费鼠标连点器有吗?需要付费吗?鼠标连点器电脑版免费推荐6款!

在数字化时代&#xff0c;鼠标连点器成为了许多用户提高工作效率、优化游戏体验的得力助手。然而&#xff0c;面对市场上琳琅满目的鼠标连点器软件&#xff0c;很多用户都会产生疑问&#xff1a;是否有免费的鼠标连点器&#xff1f;它们真的需要付费吗&#xff1f;今天&#xf…

转盘输入法-单独鼠标版本

序 转盘输入法&#xff0c;给你的聊天加点新意。它不用常见的九宫格或全键盘&#xff0c;而是把字母摆在圆盘上&#xff0c;一滑一滑&#xff0c;字就出来了&#xff0c;新鲜又直接。 单独鼠标版本GIF演示 演示软件下载 转盘输入法https://download.csdn.net/download/u0146…

优化LabVIEW代码以提高软件性能

优化LabVIEW代码对于提高软件性能、减少执行时间和资源消耗至关重要。以下是一些具体的策略和方法&#xff0c;可以帮助LabVIEW程序员优化代码&#xff1a; 1. 代码结构和模块化 使用子VI&#xff1a;将重复使用的代码段封装成子VI&#xff0c;提高代码的可读性和可维护性。 避…

为什么https比http更安全

读完本文&#xff0c;希望你能明白&#xff1a; HTTP通信存在什么问题HTTPS如何改进HTTP存在那些问题HTTPS工作原理是什么 一、什么是HTTPS HTTPS是在HTTP上建立SSL加密层&#xff0c;并对传输数据进行加密&#xff0c;是HTTP协议的安全版。现在它被广泛用于万维网上安全敏感…

Python酷库之旅-第三方库Pandas(005)

目录 一、用法精讲 7、pandas.read_clipboard函数 7-1、语法 7-2、参数 7-3、功能 7-4、返回值 7-5、说明 7-6、用法 7-6-1、代码示例 7-6-2、结果输出 8、pandas.DataFrame.to_clipboard函数 8-1、语法 8-2、参数 8-3、功能 8-4、返回值 8-5、说明 8-6、用法…

C语言自定义类型——联合体、枚举

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、联合体&#xff08;一&#xff09;、联合体的声明&#xff08;二&#xff09;、联合体的特点&#xff08;三&#xff09;、联合体大小的计算&#xff01;&a…

提取重复数据

直接上控制台代码&#xff1a; Module Module1Sub Main()Console.WriteLine("请输入数据&#xff0c;以""&#xff0c;""相隔&#xff1a;")Dim str As String Console.ReadLineDim result From x In str.Split(",")Group By x Int…

【吊打面试官系列-MyBatis面试题】MyBatis 实现一对一有几种方式?具体怎么操作的?

大家好&#xff0c;我是锋哥。今天分享关于 【MyBatis 实现一对一有几种方式?具体怎么操作的&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; MyBatis 实现一对一有几种方式?具体怎么操作的&#xff1f; 有联合查询和嵌套查询,联合查询是几个表联合查询,只查询…

Springboot助农农产品销售系统-计算机毕业设计源码16718

摘要 SpringBoot助农农产品销售系统旨在通过利用SpringBoot框架开发一个便捷高效的农产品销售平台。该系统包括用户注册登录、商品浏览、购物车管理、订单生成、支付功能等模块。通过整合支付接口、地图定位、推荐系统等技术&#xff0c;提供给用户更好的购物体验。本文介绍了…

宿舍报修小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;基础数据管理&#xff0c;论坛管理&#xff0c;故障上报管理&#xff0c;新闻信息管理&#xff0c;维修人员管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;新闻信息…

B组亚太赛数学建模

问题1 1.对训练数据集进行数据清洗&#xff0c;处理缺失值和异常值。 2.采用散点图作为可视化手段。 3.采用皮尔逊相关系数进行相关性分析。 4.提出预防措施。 问题2 1.采用k-means聚类算法将洪水概率分为高中低三个群组。 2.通过线性回归模型计算特征权重。 3.选择特定…

SpringBoot | 大新闻项目源码打包

对于一个完成好的后端项目&#xff0c;如何进行打包发送给其他人&#xff0c;在电脑上进行查看 1.在pom.xml添加&#xff1a; <build><plugins> <!-- 打包插件--><plugin><groupId>org.springframework.boot</groupId><art…

刷题之移除元素(leetcode)

移除元素 这题简单题&#xff0c;但是前面思路是先找到左边第一个不是val的&#xff0c;和右边第一个不是val的&#xff0c;进行交换&#xff0c;边界条件没有处理好&#xff0c;导致报错&#xff08;水平真菜&#xff09; 也可以直接把left是val的与right进行交换&#xf…

CTFHUB-SSRF-302跳转 Bypass

开启题目&#xff0c;页面空白 尝试访问127.0.0.1/flag.php页面 ?url127.0.0.1/flag.php 提示&#xff1a;不允许企业内部IP访问&#xff0c;使用file协议获取其源码&#xff0c;得到flag.php页面源码 ?urlfile:///var/www/html/flag.php 与之前一样&#xff0c;通过REMOT…

将循环转化为递归的三种方法,求1+2+3……+n等差数列

解法一&#xff1a;使用公共变量s&#xff0c;递归循环1~n加到s上 #include<bits/stdc.h> using namespace std; int n,s; void fun(int i){if(i<n){ssi;fun(i1);}}int main(){cin>>n;fun(1);cout<<s;return 0; } 解法二&#xff1a;通过层层累加&#x…

隐藏的h1写法(以图换字)

所谓以图换字&#xff0c;即直接使用一张图片或背景&#xff0c;没有文字。我们知道&#xff0c;蜘蛛爬取时是不会获取图片上的内容的&#xff0c;但是如果是添加上文字&#xff0c;即便使用一些字体&#xff0c;也可能达不到图片的显示效果。如何将用户体验与SEO优化相兼容呢&…

【国产开源可视化引擎Meta2d.js】铅笔

铅笔 铅笔是可以任意涂鸦的绘图小工具 在线体验&#xff1a; 乐吾乐2D可视化 示例&#xff1a; // 开始铅笔绘画 meta2d.drawingPencil();// 鼠标抬起结束// 停止铅笔绘画&#xff08;关闭铅笔绘画状态&#xff09; meta2d.stopPencil(); 国产开源 乐吾乐潜心研发&#xff…

微信小程序UGC类功能场景内容安全识别检测实现方案

概念普及 最近开发了一个小程序&#xff0c;属于同城信息发布类的&#xff0c;提交上架的时候&#xff0c;说需要补充社交-笔记类目。 补充完再次提审&#xff0c;又说是项目包含UGC类功能场景。所谓的UGC类功能&#xff0c;就是指用户可以在平台上自由发布信息&#xff0c;这…

相关向量机RVM算法介绍继承sklearn-SVM-API实现回归预测算例

一、相关向量机RVM与支持向量机SVM对比 1、相关向量机&#xff08;RVM&#xff09; ①定义与原理 相关向量机&#xff08;Relevance Vector Machine, RVM&#xff09;是一种基于概率模型的机器学习算法&#xff0c;主要用于分类和回归分析。基于稀疏贝叶斯学习框架&#xff…