Spring Boot 项目中,JDK 动态代理和 CGLIB 动态代理的使用

【Spring Boot实战与进阶】AOP的两种动态代理(JDK和Cglib) 在这个部分总结了2019年到目前为止Java常见面试问题,取其面试核心编写成这份文档笔记,从中分析面试官的心理,摸清面试官的“套路”,可以说搞定90%以上的Java中高级面试没一点难度。本节总结的内容涵盖了:消息队列、Redis缓存、分库分表、读写分离、设计高并发系统、分布式系统、高可用系统、SpringCloud微服务架构等一系列互联网主流高级技术的知识点。(上述只是一个整体目录大纲,每个点里面都有如下所示的详细内容,从面试问题——分析面试官心理——剖析面试题——完美解答的一个过程) 阅读详情

在 Spring Boot 项目中,JDK 动态代理和 CGLIB 动态代理都是实现 AOP (面向切面编程) 的重要技术。 它们的主要区别在于代理对象的生成方式和适用范围。 下面详细介绍它们的使用场景:

1. JDK 动态代理 (JDK Dynamic Proxy)

  • 原理:

    • JDK 动态代理是 Java 提供的内置代理机制,它通过反射在运行时动态地生成代理类。
    • 代理类会实现目标类实现的接口,并将接口中的方法调用委托给一个 InvocationHandler 对象来处理。
    • InvocationHandler 接口负责实现具体的增强逻辑,例如日志记录、安全检查、事务管理等。
  • 使用场景:

    • 目标类实现了接口: 如果目标类实现了接口,则 Spring AOP 默认使用 JDK 动态代理。
    • 简单 AOP 场景: 适用于简单的 AOP 场景,例如只需要对接口方法进行增强的情况。
    • 不需要代理类的构造函数: JDK 动态代理创建代理对象时,不需要调用目标类的构造函数。
  • 优点:

    • 简单易用: JDK 动态代理是 Java 内置的代理机制,使用起来比较简单。
    • 不需要第三方库: 不需要依赖第三方库。
    • 对接口友好: 代理类实现了目标类实现的接口,符合面向接口编程的思想。
  • 缺点:

    • 必须实现接口: 目标类必须实现接口,否则无法使用 JDK 动态代理。
    • 只能代理接口方法: 只能代理接口中定义的方法,无法代理类自身定义的方法。
  • 示例代码:

    // 接口
    interface MyInterface {
        void doSomething();
    }
    
    // 实现类
    class MyClass implements MyInterface {
        @Override
        public void doSomething() {
            System.out.println("MyClass is doing something...");
        }
    }
    
    // 调用处理器
    class MyInvocationHandler implements InvocationHandler {
        private Object target; // 被代理的对象
    
        public MyInvocationHandler(Object target) {
            this.target = target;
        }
    
        @Override
        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;
        }
    }
    
    // 使用 JDK 动态代理
    public class JDKDynamicProxyExample {
        public static void main(String[] args) {
            MyInterface target = new MyClass(); // 创建目标对象
            MyInvocationHandler handler = new MyInvocationHandler(target); // 创建调用处理器
    
            // 创建代理对象
            MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
                    MyInterface.class.getClassLoader(),
                    new Class[] {MyInterface.class},
                    handler
            );
    
            proxy.doSomething(); // 调用代理对象的方法,会被拦截
        }
    }
    

2. CGLIB 动态代理 (CGLIB Dynamic Proxy)

  • 原理:

    • CGLIB (Code Generation Library) 是一个强大的、高性能的代码生成库。
    • CGLIB 动态代理通过在运行时动态地生成目标类的子类来实现代理。
    • 代理类会继承目标类,并重写目标类的方法,在重写的方法中实现增强逻辑。
    • CGLIB 动态代理不需要目标类实现接口,可以直接代理类。
  • 使用场景:

    • 目标类没有实现接口: 如果目标类没有实现接口,则 Spring AOP 使用 CGLIB 动态代理。
    • 需要代理类自身定义的方法: 需要代理类自身定义的方法,而不仅仅是接口方法。
    • 需要更高的性能: 在某些情况下,CGLIB 动态代理的性能可能比 JDK 动态代理更好。
  • 优点:

    • 不需要实现接口: 目标类不需要实现接口,可以直接代理类。
    • 可以代理类自身定义的方法: 可以代理类自身定义的方法,而不仅仅是接口方法。
    • 性能较好: 在某些情况下,CGLIB 动态代理的性能可能比 JDK 动态代理更好。
  • 缺点:

    • 需要第三方库: 需要依赖 CGLIB 库。
    • 实现复杂: CGLIB 动态代理的实现比较复杂,需要生成目标类的子类。
    • final 方法无法代理: 无法代理被 final 修饰的方法。
    • 对构造函数有要求: CGLIB 创建代理对象时,需要调用目标类的构造函数。 如果目标类没有无参构造函数,则需要手动指定构造函数。
  • 示例代码:

    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.Method;
    
    // 目标类
    class MyClass {
        public void doSomething() {
            System.out.println("MyClass is doing something...");
        }
    }
    
    // 方法拦截器
    class MyMethodInterceptor implements MethodInterceptor {
        @Override
        public 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;
        }
    }
    
    // 使用 CGLIB 动态代理
    public class CGLIBDynamicProxyExample {
        public static void main(String[] args) {
            Enhancer enhancer = new Enhancer(); // 创建 Enhancer 对象
            enhancer.setSuperclass(MyClass.class); // 设置超类
            enhancer.setCallback(new MyMethodInterceptor()); // 设置回调
    
            MyClass proxy = (MyClass) enhancer.create(); // 创建代理对象
    
            proxy.doSomething(); // 调用代理对象的方法,会被拦截
        }
    }
    

3. Spring Boot 中的 AOP 配置

在 Spring Boot 项目中,可以通过以下方式配置 AOP:

  • 添加 AOP 依赖:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    
  • 编写切面类:

    @Aspect
    @Component
    public class LoggingAspect {
    
        @Before("execution(* com.example.demo.service.*.*(..))")
        public void beforeAdvice(JoinPoint joinPoint) {
            System.out.println("Before executing method: " + joinPoint.getSignature());
        }
    }
    
  • 配置代理方式:

    默认情况下,Spring AOP 会根据目标类是否实现了接口来选择使用 JDK 动态代理或 CGLIB 动态代理。 可以通过 @EnableAspectJAutoProxy 注解的 proxyTargetClass 属性来强制使用 CGLIB 动态代理。

    @Configuration
    @EnableAspectJAutoProxy(proxyTargetClass = true) // 强制使用 CGLIB 动态代理
    public class AopConfig {
        // ...
    }
    

总结:

特性JDK 动态代理CGLIB 动态代理
目标类要求必须实现接口不需要实现接口
代理对象生成方式实现接口继承类
性能一般较好
易用性简单复杂
是否需要第三方库否是 (net.sf.cglib)
适用场景目标类实现了接口,简单 AOP 场景目标类没有实现接口,需要代理类自身定义的方法,性能要求较高
@EnableAspectJAutoProxy默认值:falseproxyTargetClass = true

在实际开发中,Spring AOP 会自动选择合适的代理方式。 如果没有特殊需求,可以使用默认配置。 如果需要强制使用 CGLIB 动态代理,可以设置 @EnableAspectJAutoProxy(proxyTargetClass = true)。

SpringBoot(二十八)SpringBoot实现动态代理模式 JDK 和 CGLIB 都是在运行期生成字节码,JDK 是直接写 class 字节码,CGLIB 使用 ASM 框架写 class 字节码,CGLIB 代理实现更复杂,CGLIB 生成代理类的效率比 JDK 生成代理类效率低。JDK 调用代理方法,是通过反射机制调用,CGLIB 是通过 FastClass 机制直接调用方法,CGLIB 的被代理类执行效率比 JDK 的被代理类更高。JDK 动态代理生成的代理对象是实现了被代理对象的接口,CGLIB 动态代理生成的代理对象是继承了被代理对象。 阅读详情

相关推荐

SpringBoot选择CGLIB作为默认动态代理

Spring Boot从2.x版本开始,默认使用CGLIB作为动态代理实现。这是因为在Spring Boot 2.x中,为了解决使用JDK动态代理可能导致的类型转换异常问题,选择了CGLIB作为默认的代理方式。

小天一直在路上 2011

【Java小记】Springboot 动态代理Bean

创建一个自定义的根接口,实现该接口或者其子接口的类都将被代理。为了方便对MyInterface接口的不同子接口做不同的增强过程,将增强的处理过程从InvocationHandler中分离出来。单独创建一个MyInterfaceProcessor接口。getType()用于指定该Processor处理的MyInterface接口(也可以通过注解等形式指定)。

园土天双的博客 2487

惊人!Spring5 AOP 默认使用Cglib? 从现象到源码深度分析

Spring 5.x 中 AOP 默认依旧使用 JDK 动态代理。SpringBoot 2.x 开始,为了解决使用 JDK动态代理可能导致的类型转化异常而默认使用 CGLIB。在 SpringBoot 2.x 中,如果需要默认使用 JDK动态代理可以通过配置项spring.aop.proxy-target-class=false来进行修改,proxyTargetClass配置已无效。

sdujava2011 1335

spring boot 动态代理

springboot团队之所以默认的代理模式设置成cglib代理,看看spring的官方团队是怎么解释的 This was changed in 1.4 (see https://github.com/spring-projects/spring-boot/issues/5423). We’ve generally found cglib proxies less likely to cause unexpected cast exceptions. 他们认为使用cglib更不容易出现转换错误 整体逻

sunshinezx8023的博客 7180

场景应用:为什么SpringBoot使用cglib作为默认动态代理 ?AOP使用jdk动态代理会有什么问题 ?

现在,让我们看看为什么Spring Boot默认选择CGLIB作为动态代理方式以及AOP中使用JDK动态代理可能会引发问题。这些示例帮助解释了为什么Spring Boot选择CGLIB作为默认动态代理方式,并强调了AOP使用JDK动态代理可能引发的一些问题。让我们首先考虑性能。当涉及到Spring Boot的默认动态代理选择和AOP使用JDK动态代理可能引发的问题时,让我们通过具体的代码示例来更好地理解这些概念。如果目标类没有实现接口,或者需要代理非接口类的方法,那么JDK动态代理就无法胜任。

流楚丶格念的博客 6738

SPSS新手教程—两步聚类之结果解读

在《详解SPSS两步聚类之参数设置》一文中,我们已经了解了两步聚类的优点、分析原理,以及参数设置的技巧。 在本节中,会对IBM SPSS Statistics聚类后的结果进行解读,其中会涉及到最终聚类的结果、聚类的质量、变量重要性、聚类特征的解读。 如图1所示,我们先来回顾下本例数据在参数设置面板中的详细设置。 图1:二阶聚类设置 一、数值结果 根据上述参数设置,得到如下的数值分析结果。 首先看到自动聚类结果,如图2所示为聚类的透视表结果,展示了不同聚类数目下的BIC、BIC变化量、BIC变

nekonekoboom的博客 3万+

springboot2.x默认使用的代理是cglib代理

背景 因为项目优化,打算写个日志的切面类,于是起了个springboot 工程,在这里面测试。结果在springboot 里面测试正常,能正确打印日志,但是把代码复制到实际项目中,在进入切面打印日志的时候总是报错,报空指针错误。经调试发现每次都是在获取注解上的属性时报错。当时百思不得解。后来灵光一闪,想到可能是项目中获取到的是接口方法,而springboot是实现类的method ,所以可以拿到注解的属性。但是仔细一想,Springboot里面也是接口,难道不应该走JDK动态代理吗?那拿到这个方法的应该也是

m0_67402564的博客 315

ISP图像处理Verilog仿真框架搭建(附代码)

基于Verilog的图像处理仿真框架搭建

路漫漫其修远兮,吾将上下而求索 1894

静态代理与动态代理

1.静态代理模式 2.动态代理模式

weixin_43189971的博客 231

Python实现课程时间表

用Python实现课程表功能

life is like a play 2040

【Qualcomm高通音频】音效调试_录音文件播放有杂音,如何定位原因?

一、录音播放数据处理过程介绍 (1)TX方向 麦克风(硅麦克风或者主机体麦克风)采集模拟音频信号,经过内部CODEC芯片中的adc转换为数字信号,在经过高通音频DSP处理音效后编码为wav/aac/amr/mp3等格式文件。 (2)RX方向 音频文件经过解码、重采样还原为pcm数据,经过DSP处理音效后送到内部CODEC,然后经过DAC转换为模拟信号,送到喇叭。 二、分析步骤 1...

crow_ch的博客 5971

(学习笔记)SpringBoot基础(四)Spring Boot 的 AOP 支持

摘要: Spring Boot通过spring-boot-starter-aop简化了AOP(面向切面编程)的整合,自动引入依赖并隐式开启代理支持,无需手动配置。AOP用于解耦横切关注点(如日志、事务),通过动态代理将通用逻辑织入业务方法。核心概念包括切面(Aspect)、切入点(Pointcut)、通知(Advice)等,支持5种通知类型(如前置、环绕)。相比传统Spring需手动配置依赖和注解,Spring Boot实现了零配置,默认使用CGLIB代理,开发者只需定义切面类即可快速实现功能增强。

qq_45913654的博客 1218

用 SAP XCO XLSX 模块优雅读 Excel:坐标、选择模式与实战案例全解析

SAP ABAP Cloud 中的 XCO XLSX 模块为 Excel 文件处理提供了官方解决方案。文章介绍了三个核心概念:通过 XCO_CP_XLSX=>DOCUMENT 获取文档句柄;使用 CL_XCO_XLSX_COORDINATE 坐标系统定位单元格;利用 Selection Pattern 精确读取数据区域。这些功能在 RAP 批量导入等业务场景中尤为实用,相比传统方案更加简洁可靠。文章还分享了真实项目中的最佳实践,如动态列定位和相对偏移技巧,帮助开发者构建更健壮的 Excel 导入逻辑。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 191

JDK动态代码出错,改用GCLib动态代码实现方式

背景 MQCPConsumeCarMsg implements MQCPMessageListener { } MQCPConsumeCarMsg类实现了MQCPMessageListener这个接口,在自动注入 @AutoWired MQCPConsumeCarMsg mQCPConsumeCarMsg 的时候,会出现如下错误 : the bean ‘MQCPConsu...

onedaycbfly的专栏 826

Python 爬虫实战:爬取去哪儿网酒店评价,提取住宿体验关键词

本文介绍了基于去哪儿网酒店评价数据的爬取与分析方法。首先通过分析网页结构和数据加载机制,定位到评价数据的JSON接口及关键参数。然后使用Python搭建爬虫环境,实现多页评价数据的批量采集与存储,并通过反爬策略确保数据获取的稳定性。在文本分析环节,采用jieba分词和TF-IDF算法提取高频关键词,结合词云可视化展示用户关注点。分析结果显示位置、服务、卫生是核心关注维度,同时识别出好评与差评的关键驱动因素。该方法为酒店服务优化和消费者决策提供了数据支持,并可通过扩展实现更深入的情感分析和竞品对比。

2503_91057718的博客 998

半导体工艺仿真:离子注入工艺仿真_(8).损伤和缺陷仿真

离子注入工艺在半导体制造中是一个重要的步骤,用于在半导体材料中引入特定的掺杂剂。然而,离子注入过程中不可避免地会产生损伤和缺陷,这些损伤和缺陷会直接影响器件的性能和可靠性。因此,对离子注入工艺中的损伤和缺陷进行仿真研究是必不可少的。本节将详细介绍如何使用仿真软件对离子注入过程中的损伤和缺陷进行建模和分析。

2401_87715305的博客 1338

Java静态代理和动态代理

代理模式是一种结构性模式。代理模式为一个对象提供了一个替身,以控制对这个对象的访问。即通过代理对象访问目标对象,可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。静态代理是定义父类或者接口,然后被代理对象(即目标对象)与代理对象一起实现相同的接口或者继承相同的父类。代理对象与目标对象实现相同的接口,然后通过调用相同的方法来调用目标对象的方法。职责清晰,符合单一职责原则。

qq_43070052的博客 1218

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

spring-aop中对象MethodSignature的getParameterNames()返回结果为null

spring动态代理是jdk,所以成功获取参数名的方法是因为动态代理使用的是cglib,所以无需开启上面的配置都行,所以我们只需要在项目中强制使用cglib就行。 <aop:aspectj-autoproxy proxy-target-class="true"/> 而在spring-boot项目中,是默认采用cglib实现动态代理的,所以不用添加配置,这就是我们在老项目写好的aop...

weixin_43343423的博客 2363

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

spring aop两种代理混用问题

工作繁忙,但是遇到问题还是要总结积累下来,今天项目中出现了代理混用的问题,解决之后记录一下对两种代理方式的学习理解。 一,首先复习一下两种代理 JDK动态代理 和 cglib代理 1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP 2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP 3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换 Spring AOP的原理是 JDK 动态代理和CGLIB字节码增强技术,前者.

babyLetsGo的博客 1267

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

【图文详解】SpringBoot项目启动报错:The bean ‘xxxServiceImpl‘ could not be injected as a ‘xxxServiceImpl‘ ...

问题描述: 项目启动报错:The bean ‘xxxServiceImpl’ could not be injected as a ‘cn.xxxx.service.xxxServiceImpl’ because it is a JDK dynamic proxy that implements:

二十四日的博客 3666

使用@Aspect面向切面编程,SpringBoot的AOP编程和动态代理

1.了解 1. 动态代理和静态代理 静态代理: 由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。 动态代理: 动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。 2.jdk代理和cglib代理 动态代理又可分为:JDK...

zzzgd_666的博客 991

Spring学习:SpringAOP面向切面编程

SpringAOP的底层原理就是通过动态代理来实现的,动态代理又是从静态代理演变而来的,动态代理是为了解决静态代理中代理类需要自己声明和一个代理类只能代理一个类型这两个弊端。动态代理可通过JDK动态代理和CGLIB动态代理两种方式实现,两种方式在实现和效率上有一定的区别。

2201_75450136的博客 838

SpringBoot简单实现aop

aop的简单实现

alashanMt的博客 4495

收集一些优秀的文章(永无止境地更新)

把平时看到写得好的文章记录一下,自己没事的时候也能好好多看几遍,也学习一下1.spring中IOC的原理:https://www.tianmaying.com/tutorial/spring-ioc2.spring中的AOP:Spring AOP详解图解AOP3.由于spring AOP是基于动态代理的,所以下面找了一下jdk动态代理和cglb动态代理的文章:jdk和cglib的2种实现以及二者的...

Crazer_cy的博客 356

SpringBoot使用AOP完成对全局接口访问次数的统计

由于项目中需要统计全局接口访问次数,所以简单使用AOP实现了该功能。

Devbor的博客 4698
上一篇: 反射机制在项目中的应用场景
下一篇: CompletableFuture 和多线程的关系
冰糖心书房
博客等级 码龄15年 6014粉丝 690原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰糖心书房

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值