探究Java spring中jdk代理和cglib代理!
面对新鲜事物,我们要先了解在去探索事物的本质-默
目录
一.介绍二者代理模式
1.1.Jdk代理模式
1.2cglib代理模式
1.3二者区别
1.3.1有无接口
1.3.2灵活性
1.4对于两种代理模式的总结
1.4.1jdk代理模式
1.4.2cglib代理模式
二.两种代理模式应用场景
2.1jdk代理模式应用场景
2.1.1基于接口的代理
2.1.2细粒度的方法拦截
2.2cglib代理模式应用场景
2.2.1非基于接口的代理
2.2.2覆盖父类中的方法
2.2.3高性能的代理
三.代码演示
3.1jdk代理模式
3.1.1源码
3.2思路解释
3.2cglib代理模式
3.2.1源码
3.2.1思路解释
一.介绍二者代理模式
1.1.Jdk代理模式
JDK代理是通过接口实现的动态代理方式。当目标类实现了至少一个接口时,Spring AOP会使用JDK代理。JDK代理通过在运行时创建一个实现了目标接口的代理类来实现代理功能。代理对象和目标对象实现了同一个接口,因此只能代理接口中定义的方法。
1.2cglib代理模式
CGLIB代理是通过继承实现的动态代理方式。当目标类没有实现任何接口时,Spring AOP会使用CGLIB代理。CGLIB代理通过在运行时创建目标类的子类来实现代理功能。代理对象继承自目标对象,并覆盖了目标对象的非final方法,因此可以代理目标对象的所有方法。
1.3二者区别
1.3.1有无接口
JDK代理要求目标类必须实现接口,而CGLIB代理不需要,可以代理普通的Java类。
1.3.2灵活性
JDK代理基于接口,适用于对接口的代理,更加灵活,但无法代理没有接口的类。
CGLIB代理是通过生成目标类的子类来实现代理,适用于对类的代理。CGLIB代理具有更高的性能,因为它不需要通过反射调用目标对象的方法。
1.4对于两种代理模式的总结
1.4.1jdk代理模式
JDK 动态代理是基于接口的代理方式。它通过创建一个实现了目标接口的代理类,并在代理类中实现代理逻辑。代理类在运行时动态生成,并在其中调用原始对象的方法
JDK 动态代理通过 java.lang.reflect.Proxy
类和 java.lang.reflect.InvocationHandler
接口来实现。代理对象是在运行时动态生成的。
无法代理非公有类:JDK 动态代理不能代理那些声明为 final 的类,因为 final 类不能被继承。另外,由于代理类是在运行时动态生成的,因此也无法代理那些没有默认构造函数的类。
方法拦截:代理对象在调用方法时,会将方法调用转发给 InvocationHandler
的实现类,在这个实现类中可以添加自定义的逻辑,完成方法的拦截、增强等操作。
性能相对较低:相比于 CGLIB 动态代理,JDK 动态代理的性能较低。这主要是因为 JDK 动态代理需要通过反射来调用目标对象的方法。
总的来说,JDK 动态代理是一种比较常用的代理方式,适用于代理接口的场景,易于使用和理解。但它的局限性在于只能代理实现了接口的类,并且在性能方面稍逊于 CGLIB 动态代理。
1.4.2cglib代理模式
CGLIB 动态代理是一种基于继承的代理方式。它通过创建目标类的子类来实现代理。代理类继承自目标类,并重写其中的方法,在重写的方法中添加了增强逻辑。
类代理:CGLIB 动态代理可以代理类,无论是否实现了接口。这使得它可以代理那些没有实现接口的类,不包括 final 类。
代理生成:CGLIB 动态代理使用字节码生成库来创建目标类的子类。代理类在运行时动态生成,并且不需要目标类实现任何接口。
方法拦截:被代理的方法在执行时,会调用代理类中的方法。这样,我们可以在代理类中添加拦截器(MethodInterceptor
),并在拦截器中实现自定义的逻辑。
性能相对较高:相比于 JDK 动态代理,CGLIB 动态代理的性能更高。这是因为 CGLIB 通过继承来实现代理,避免了反射调用的开销。
对于 final 方法和私有方法的限制:CGLIB 默认无法代理 final 方法,因为 final 方法无法被重写。此外,CGLIB 也不能代理私有方法,因为代理类无法访问目标类的私有方法。但是可以通过设置 CGLIB 的 Enhancer 对象的 setUseReflection(true)
方法来强制代理私有方法。这样一来,CGLIB 将使用反射调用私有方法,但这可能会导致性能下降。
需要注意的是,CGLIB 代理依赖于字节码生成,在代理类生成时会占用一定的时间和内存。
总结来说,CGLIB 动态代理适用于代理类的场景,可以代理没有实现接口的类,并且具有较高的性能。
二.两种代理模式应用场景
2.1jdk代理模式应用场景
2.1.1基于接口的代理
如果目标对象实现了接口,可以使用JDK动态代理。它要求目标对象实现一个接口,并且生成的代理对象也会实现相同的接口。
2.1.2细粒度的方法拦截
JDK动态代理可以在目标对象的方法调用前后添加额外的逻辑。例如,在方法调用前打印日志、进行权限验证或事务管理等
2.2cglib代理模式应用场景
2.2.1非基于接口的代理
CGLIB动态代理可以代理没有实现接口的类。因此,当目标对象没有实现任何接口时,可以使用CGLIB动态代理。
2.2.2覆盖父类中的方法
CGLIB动态代理通过继承目标类并覆盖其中的方法来创建代理对象。这使得它可以代理目标类中的非公有方法。
2.2.3高性能的代理
相比JDK动态代理,CGLIB动态代理通常具有更高的性能,因为它直接操作字节码而不需要通过反射调用方法。
三.代码演示
3.1jdk代理模式
3.1.1源码
package com.daili.jdk;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** @author lz* @create 2023-08-21 9:33*/
public interface UserService {void saveUser(String username);
}
class UserServiceImpl implements UserService {public void saveUser(String username) {System.out.println("Saving user: " + username);}
}class UserServiceProxy implements InvocationHandler {private Object target;public UserServiceProxy(Object target) {this.target = target;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("Before method: " + method.getName());Object result = method.invoke(target, args);System.out.println("After method: " + method.getName());return result;}
}class Main {public static void main(String[] args) {UserService userService = new UserServiceImpl();UserService proxy = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(),userService.getClass().getInterfaces(),new UserServiceProxy(userService));proxy.saveUser("刘兵");}
}
3.2思路解释
- 定义了一个接口
UserService
,其中包含了一个抽象方法saveUser(String username)
。 - 实现了接口
UserService
的具体类UserServiceImpl
,该类实现了saveUser
方法,用于保存用户信息。 - 创建了一个代理类
UserServiceProxy
,实现了InvocationHandler
接口。在invoke
方法中,对目标方法进行前置和后置处理,即在目标方法执行前输出 "Before method: " + 方法名,在目标方法执行后输出 "After method: " + 方法名。 - 在
Main
类的main
方法中,创建了一个UserServiceImpl
的实例。 - 通过
Proxy.newProxyInstance()
方法创建代理对象,传入目标对象的类加载器、接口数组和UserServiceProxy
的实例。返回的代理对象将会实现UserService
接口。 - 调用代理对象的
saveUser("John")
方法,实际上会触发代理对象的invoke
方法,从而实现了动态代理。
在代码执行过程中,代理对象的 invoke
方法会先输出 "Before method: saveUser",然后调用目标对象的 saveUser
方法,最后输出 "After method: saveUser"。
通过 JDK 动态代理,可以在不修改目标对象代码的情况下,对其方法进行增强、添加日志等操作。
3.2cglib代理模式
3.2.1源码
package com.daili.cglib;import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/*** @author lz* @create 2023-08-21 9:49*/
public class UserService {public void saveUser(String username) {System.out.println("Saving user: " + username);}
}
class UserServiceInterceptor implements MethodInterceptor {@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("Before method: " + method.getName());Object result = proxy.invokeSuper(obj, args);System.out.println("After method: " + method.getName());return result;}static class Main {public static void main(String[] args) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(UserService.class);enhancer.setCallback(new UserServiceInterceptor());UserService proxy = (UserService) enhancer.create();proxy.saveUser("刘兵");}
}
}
3.2.1思路解释
- 定义了一个类
UserService
,其中包含了一个方法saveUser(String username)
,用于保存用户信息。 - 创建了一个代理类
UserServiceInterceptor
,实现了MethodInterceptor
接口。在intercept
方法中,对目标方法进行前置和后置处理,即在目标方法执行前输出 "Before method: " + 方法名,在目标方法执行后输出 "After method: " + 方法名。使用MethodProxy
对象调用原始方法。 - 在
Main
类的main
方法中,创建了一个Enhancer
对象。 - 通过
enhancer.setSuperclass(UserService.class)
设置目标类为UserService
。 - 通过
enhancer.setCallback(new UserServiceInterceptor())
设置回调处理器为UserServiceInterceptor
的实例。 - 调用
enhancer.create()
方法返回代理对象,将其转换为UserService
类型。 - 调用代理对象的
saveUser("John")
方法,会触发代理对象的intercept
方法,从而实现了动态代理。
在代码执行过程中,代理对象的 intercept
方法会先输出 "Before method: saveUser",然后调用目标对象的 saveUser
方法,最后输出 "After method: saveUser"。
通过 CGLIB 动态代理,可以在不修改目标对象代码的情况下,对其方法进行增强、添加日志等操作。与 JDK 动态代理不同的是,CGLIB 动态代理可以代理类而不仅限于接口。
相关文章:

探究Java spring中jdk代理和cglib代理!
面对新鲜事物,我们要先了解在去探索事物的本质-默 目录 一.介绍二者代理模式 1.1.Jdk代理模式 1.2cglib代理模式 1.3二者区别 1.3.1有无接口 1.3.2灵活性 1.4对于两种代理模式的总结 1.4.1jdk代理模式 1.4.2cglib代理模式 二.两种代理模式应用场景 2.1jd…...
反转链表(C++)
1、迭代法的一种写法 ListNode* reverse_linkList(ListNode* head){if(head nullptr || head->next nullptr) return head;ListNode* begin nullptr;ListNode* mid head;ListNode* end head->next;while(true){mid->next begin;if(end nullptr){break;}begin …...
适配器模式:让不兼容的接口协同工作
在面向对象设计中,适配器模式是一种常见的结构型设计模式。它允许将不兼容的接口转换成客户端所期望的另一个接口,从而使不同的类协同工作。适配器模式的主要目的是解决不同接口之间的兼容性问题,同时也提高了代码的可重用性和灵活性。 问题…...
【1day】复现Milesight-VPNserver.js 任意文件读取漏洞
目录 一、漏洞描述 二、影响版本 三、资产测绘 四、漏洞复现 一、漏洞描述 Milesight路由器-VPN是由Milesight Technology Co., Ltd.开发的一种集成了VPN功能的路由器产品。它旨在为用户提供安全、可靠的远程访问和连接解决方案。Milesight-VPNserver.js存在任意文件读取…...
前端代码规范
1 husky husky用于绑定git hooks,在指定时机执行想要的命令 {"husky": {"hooks": {"pre-commit": "lint-staged" }} }需要手动修改.husky文件内容: . "$(dirname -- "$0")/_/husky.sh"n…...
Java接入文心一言
文章目录 文心一言应用创建接口对接接口文档代码示例依赖 常量类实体类 结束语 文心一言应用创建 首先需要先申请文心千帆大模型,申请地址:文心一言 (baidu.com),点击加入体验,等通过审核之后就可以进入文心千帆大模型后台进行应…...

信息管理系统三级等保的一些要求
一、前言 在做一些互联网系统或面向互联网的系统时,需要进行备案,需要满足网络信息安全维护规章及有关规章制度要求,才能发布到互联网。所以在做系统的需求分析时,往往需要把信息管理系统三级等保的需求加上,方便开发…...
第六届“蓝帽杯”电子取证模块(初赛)解析+全资源一次性分享
前言:资源一次性分享 手机+电脑+exe+内存四个模块,我自己在网上也找了很久,才把资源找齐全,题目我也整理在这里,方便大家训练。 目录...
《Go 语言第一课》课程学习笔记(九)
常量:Go 在“常量”设计上的创新有哪些? Go 语言在常量方面的创新包括下面这几点: 支持无类型常量;支持隐式自动转型;可用于实现枚举。 常量 Go 语言的常量是一种在源码编译期间被创建的语法元素。这是在说这个元素…...
docker 安装nginx 和 elasticsearch ik 自定义分词
1、切换到/mydata 文件夹 创建 nginx 目录 mkdir nginx 2、运行 docker run --name nginx -p 80:80 -d nginx:1.22.0 3、复制docker 里面的nginx配置到 外面的nginx/conf 下面 docker cp nginx:/etc/nginx /mydata/nginx 4、把 /mydata/nginx下面的nginx 改…...

谈谈收音机的发展
目录 1.什么是收音机 2.收音机的工作原理 3.收音机的发展历史 4.收音机的历史作用 1.什么是收音机 收音机是一种电子设备,用于接收和播放广播电台的无线电信号。它是人们获取各种音乐、新闻、娱乐和其他广播节目的常用设备。 收音机通常由以下几个部分组成&…...

QTreeWidget——信号处理
文章目录 基本属性信号一、信号种类二、信号测试1、currentItemChanged、itemCollapsed、itemExpanded三个信号的测试2、itemActivated信号3、 itemChanged信号4、其余信号的测试代码(包含以上代码) 基本属性 信号 一、信号种类 //当前项发生变化时触…...

【Java从入门到精通|1】从特点到第一个Hello World程序
写在前面 在计算机编程领域,Java是一门广泛应用的高级编程语言。它以其强大的跨平台性能、丰富的库和生态系统以及易于学习的语法而备受开发者欢迎。本文将引导您逐步了解Java的特点、如何安装和配置开发环境,以及如何编写您的第一个Java程序。 一、Java…...

JAVA 读取jar包中excel模板
1、在resources路径下,新建report文件夹,放入excel模板 2、配置文件中的目录,分隔符使用 / template: /report/报告模板V1.0.xlsx3、使用getResourceAsStream()读取 XSSFWorkbook wb;try {//需要以/开始InputStream resourceAsStream this.g…...

解决方案:fatal error: openssl/bio.h: 没有那个文件或目录
出现报错如下: 出现该错误的原因有两个: 没有安装openssl或者libssl-dev库Libssl-dev版本过高,需要降级 一. 没有安装openssl或者libssl-dev库 使用指令安装openssl: 我的是已经安装完成了,所以再把libssl-dev的库也…...

【MySQL系列】ALTER语句详解,以及UPDATE,DELECT,TRUNCATE语句的使用+区别
💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤 📃个人主页 :阿然成长日记 …...
c++关键字 =delete和=default
在C的类中,有四类特殊的成员函数:① 默认构造函数;② 拷贝构造函数;③ 拷贝赋值函数(operator);④ 析构函数;它们控制着类的实例的创建、初始化、拷贝以及销毁。 (1&…...

idea 左下角的Git(Version Control)中显示Local Changes窗口
打开Local Changes窗口来查看当前Git仓库的本地变更。 使用快捷键: - Windows: Alt9 - Mac: Cmd9 解决: (1)idea打开settings (2)点击Version Control窗口选项卡,选择Commit选项,对 Use.... in…...
.net老项目中Jquery访问webservice
.net老项目中Jquery访问webservice 1. xml类型返回 jQuery.ajax({type: "POST",async: false,url: "WebService/Evection.asmx/GetCheckUpApplyEForm",contentType: "application/json",data: "{lngEvectionID:" eformSNOriginal &…...

SpringBoot项目集成ElasticSearch服务
本文已收录于专栏 《中间件合集》 目录 版本介绍背景介绍优势说明集成过程1.引入依赖2.添加配置文件3.初始化 示例说明代码结果 总结提升 版本介绍 Spring boot的版本是: 2.3.12 ElasticSearch的版本是:7.6.2 背景介绍 在我们的项目中经常会遇到对于…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...

练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...

高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...

通过 Ansible 在 Windows 2022 上安装 IIS Web 服务器
拓扑结构 这是一个用于通过 Ansible 部署 IIS Web 服务器的实验室拓扑。 前提条件: 在被管理的节点上安装WinRm 准备一张自签名的证书 开放防火墙入站tcp 5985 5986端口 准备自签名证书 PS C:\Users\azureuser> $cert New-SelfSignedCertificate -DnsName &…...

抽象类和接口(全)
一、抽象类 1.概念:如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象,这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法,包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中,⼀个类如果被 abs…...
人工智能 - 在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型
在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型。这些平台各有侧重,适用场景差异显著。下面我将从核心功能定位、典型应用场景、真实体验痛点、选型决策关键点进行拆解,并提供具体场景下的推荐方案。 一、核心功能定位速览 平台核心定位技术栈亮…...