深入理解动态代理:JDK动态代理与CGLIB动态代理

引言

在软件开发中,动态代理是一种强大的技术,它允许在运行时创建代理对象,从而为原对象添加额外的功能。Java中主要有两种动态代理机制:JDK动态代理和CGLIB动态代理。本篇文章将详细介绍这两种动态代理的概念、实现方式、应用场景,并进行对比分析。

1. 什么是动态代理?

动态代理是一种在运行时创建代理对象的技术,通过代理对象来控制对原对象的访问,能够在不修改原对象的情况下添加额外的功能。动态代理主要有以下两种实现方式:

  • JDK动态代理:基于Java反射机制,只能代理实现了接口的类。
  • CGLIB动态代理:基于字节码生成技术,可以代理没有实现接口的类。

2. JDK动态代理

原理

JDK动态代理利用反射机制在运行时生成代理类,并通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口实现代理功能。它只能代理实现了接口的类。

示例代码

接口定义
// 抽象主题接口
public interface BusinessService {void performTask();
}
实现类
// 真实主题类
public class RealBusinessService implements BusinessService {@Overridepublic void performTask() {System.out.println("Performing the main task...");}
}
动态代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;// 动态代理类
public class BusinessServiceProxy implements InvocationHandler {private Object target;public BusinessServiceProxy(Object target) {this.target = target;}public Object getProxyInstance() {return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {logBefore();Object returnValue = method.invoke(target, args);logAfter();return returnValue;}private void logBefore() {System.out.println("Log before method execution");}private void logAfter() {System.out.println("Log after method execution");}
}
客户端代码
public class JDKDynamicProxyDemo {public static void main(String[] args) {RealBusinessService realBusinessService = new RealBusinessService();BusinessServiceProxy proxy = new BusinessServiceProxy(realBusinessService);BusinessService businessService = (BusinessService) proxy.getProxyInstance();// 调用方法前后会执行增强内容businessService.performTask();}
}

输出

Log before method execution
Performing the main task...
Log after method execution

3. CGLIB动态代理

原理

CGLIB(Code Generation Library)动态代理利用ASM字节码操作框架在运行时生成代理类,它通过继承的方式代理目标对象,因此可以代理没有实现接口的类。

示例代码

实现类
// 真实主题类
public class RealBusinessService {public void performTask() {System.out.println("Performing the main task...");}
}
动态代理类
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;// 动态代理类
public class BusinessServiceProxy implements MethodInterceptor {private Object target;public BusinessServiceProxy(Object target) {this.target = target;}public Object getProxyInstance() {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(target.getClass());enhancer.setCallback(this);return enhancer.create();}@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {logBefore();Object returnValue = proxy.invokeSuper(obj, args);logAfter();return returnValue;}private void logBefore() {System.out.println("Log before method execution");}private void logAfter() {System.out.println("Log after method execution");}
}
客户端代码
public class CGLIBDynamicProxyDemo {public static void main(String[] args) {RealBusinessService realBusinessService = new RealBusinessService();BusinessServiceProxy proxy = new BusinessServiceProxy(realBusinessService);RealBusinessService businessService = (RealBusinessService) proxy.getProxyInstance();// 调用方法前后会执行增强内容businessService.performTask();}
}

输出

Log before method execution
Performing the main task...
Log after method execution

4. JDK动态代理与CGLIB动态代理的比较

相同点

  • 动态生成代理类:两者都在运行时生成代理类,能够在不修改原对象的情况下添加额外功能。
  • 增强功能:两者都可以在方法调用前后添加增强功能,如日志记录、权限控制等。

不同点

特性JDK动态代理CGLIB动态代理
代理对象只能代理实现了接口的类可以代理没有实现接口的类
实现方式基于反射机制基于字节码生成
性能调用速度稍慢,因为使用了反射调用速度较快,但创建代理对象的开销较大
依赖无需额外依赖,JDK自带需要引入CGLIB库(如Spring框架自带)
继承方式实现接口的代理通过继承的方式代理目标类

选择建议

  • JDK动态代理:如果目标类已经实现了接口,并且希望保持简单的依赖关系,使用JDK动态代理是一个好选择。
  • CGLIB动态代理:如果目标类没有实现接口或者需要更高的性能,可以考虑使用CGLIB动态代理。

5. 总结

动态代理在Java中提供了一种灵活而强大的机制,能够在运行时为目标对象添加额外的功能。JDK动态代理和CGLIB动态代理各有优势和适用场景,开发者可以根据具体需求选择合适的代理机制。

希望这篇文章对你理解动态代理有所帮助。如果觉得本文内容有价值,请点赞、收藏和关注我们,获取更多设计模式的精彩内容!

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

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

相关文章

ANSYS Electronics 电磁场仿真工具下载安装,ANSYS Electronics强大的功能和灵活性

ANSYS Electronics无疑是一款在电磁场仿真领域表现卓越的软件工具。它凭借强大的功能和灵活性,帮助用户在产品设计阶段就能精确预测和优化电磁场性能,从而极大地降低了实际测试成本,并显著提升了产品的可靠性。 这款软件不仅在电子设计领域有…

Java数组的初始化方法

Java数组的初始化方法 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!在Java编程中,数组是一种非常基础也非常重要的数据结构,它能够存储…

linux中awk,sed, grep使用(待补充)

《linux私房菜》这本书中将sed和awk一同归为行的修改这一点,虽然对,但不利于实际处理问题时的思考。因为这样的话,当我们实际处理问题时,遇到比如说统计文本打印内容时,我们选择sed还是awk进行处理呢? 也因…

VS Code 配置cmake(Linux环境)

通过sudo apt install cmake在linux上安装cmake 在Vs Code中安装这两个插件 通过命令whereis cmake获取linux中cmake的路径信息 右键CMake Tools右下角齿轮标志,选择扩展设置(Extension Settings) 注意要设置的是本地,还是远程连接…

Linux 进程间通讯

Linux IPC 方式 在Linux系统中,进程间通信(IPC)是多个运行中的程序或进程之间交换数据和信息的关键机制。Linux提供了多种IPC机制,每种机制都有其特定的用途和优势。以下是Linux上主要的IPC通信方式: 管道&#xff08…

前后端分离对软件行业及架构设计的影响

在软件开发领域,前后端分离是一种越来越流行的架构设计模式。这种方法将用户界面(前端)与服务器逻辑(后端)分离开来,允许它们独立开发、测试和部署。本文将探讨前后端分离对软件行业和架构设计的影响&#…

开发Qt上位机获取阿里云IOT设备数据(开发上位机对接阿里云IOT平台)

一、前言 随着物联网技术的快速发展,越来越多的设备开始接入互联网,实现远程监控和管理。为了方便用户实时查看设备的运行状态和数据,本文将介绍如何使用Qt框架开发一款上位机软件,调用阿里云物联网平台的API接口,获取设备最新上传的实时数据,并在Qt设计的软件界面上展示…

添加用户页面(Flask+前端+MySQL整合)

首先导入Flask库和pymysql库。Flask用于创建Web应用程序,pymysql用于连接和操作MySQL数据库。 from flask import Flask, render_template, request import pymysql创建一个Flask应用实例。__name__参数告诉Flask使用当前模块作为应用的名称。 app Flask(__name_…

打造安全的Linux环境:关键配置指南

打造安全的Linux环境:关键配置指南 Linux作为一款开源的操作系统,因其稳定性、灵活性和安全性而受到广泛欢迎。然而,即使Linux系统本身设计得相对安全,不正确的配置或管理不善也可能导致安全风险。本文将指导你如何通过关键配置来…

Android 11 系统OTA升级到旧版本(去除升级时间戳校验)

简介 由于客户要求能够通过OTA升级到旧版本因此探寻反向升级的方法。 方法一:进入recover模式 adb reboot recovery 点击Apply update from SD card 然后选择以前的OTA升级包就可以了。这种方式实测可以升级到旧的版本。但是我们的客户是通过在线升级软件进行更新…

高效管理客户的秘诀:企业如何建立稳固的客户关系

如今的竞争,从商业模式、产品、服务到销售环节,竞争已经不再是单一层面的,而是全方位的,企业需要打造全价值链竞争优势。在这个过程中,客户管理的作用是无可替代的,成为企业成功的关键因素之一。如何高效地…

基于Java的蛋糕预定系统【附源码+LW】

摘 要 当今社会进入了科技进步、经济社会快速发展的新时代。国际信息和学术交流也不断加强,计算机技术对经济社会发展和人民生活改善的影响也日益突出,人类的生存和思考方式也产生了变化。传统购物方式采取了人工的管理方法,但这种管理方法存…

0628_ARM4

练习&#xff1a; stm32流水灯 .text .global _start _start: 使能GPIOE外设时钟 0X50000A28 RCC_MP_AHB4ENSETR[4]->1 LDR R0,0x50000a28 指定操作的内存地址 LDR R1,[R0] 将R0对应的地址空间中的值读取出来 ORR R1,R1,#(0x3<<4) 将第4,5位设置为1 STR…

.net 8 集成 MinIO文件存储服务,实现bucket管理,以及文件对象的基本操作

一、准备工作 1、本地部署MinIO服务 2、创建MinIO的Access Key 3、创建.net 项目 4、下载MinIO sdk 5、相关文档 二、编写MinIO工具类 三、管理存储桶 1、MyBucket类 &#xff08;1&#xff09;判断bucket是否存在 &#xff08;2&#xff09;新建bucket &#xff08…

获取HTTP请求参数的方法

获取HTTP请求参数的方法 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们来深入探讨一下如何在Java中获取HTTP请求参数的方法。 在Web开发中&#xff0…

AI大模型-关于推理、可解释性和 LLMs_ai 推理模型

引言&#xff1a;以下文章的主题我已经思考了很久&#xff0c;我希望能我的话能引起你的思考&#xff0c;并于一些更悲观的AI评论相均衡。推理和可解释性是充满细微差别的主题——我希望这篇文章能体现这一点。 去年 GPT-4 发布时&#xff0c;我注意到出现了一个特殊的议论&…

新能源行业必会基础知识-----电力市场概论笔记-----经济学基础

新能源行业知识体系-------主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/139946830 目录 1. 什么是市场2. 电力市场机制设计的基本要求 1. 什么是市场 经济学定义 市场是供需双方交易并决定商品价格和产量的机制市场可…

JVM原理(一):JVM运行时数据区域的分析

1. 程序计数器 程序计数器是一块较小的内存空间&#xff0c;它可以看作是当前线程所执行的字节码的行号指示器。 作用 在Java虛拟机的概念模型里&#xff0c;字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令&#xff0c;它是程序控制流的指示…

ASP.NET 使用web.config配置文件的system.webServer/modules标签实现登录验证

前言 modules 标签允许你添加、删除或配置在 IIS 中运行的 HTTP 模块。HTTP 模块是处理 HTTP 请求和响应的组件&#xff0c;它们可以在请求处理管道的不同阶段执行代码。某些 system.webServer 中的设置可能只适用于 IIS 的特定模式&#xff08;如集成模式&#xff09;&#x…

Git拉取、切换分支等操作

当你在本地计算机上通过 git clone 命令克隆了一个 Git 仓库后&#xff0c;你会得到一个与远程仓库相对应的本地副本。这个本地副本包含了远程仓库的所有历史记录、分支、标签等。接下来&#xff0c;我会详细解释在该目录下启动 Terminal 并使用 Git 命令来查看和切换分支&…