当前位置: 首页 > news >正文

Cglib的Enhancer实现动态代理?

口语化回答

好的,面试官,cglib 代理相比 jdk 动态代理不同的就是不需要被代理的类去实现接口。假设我们现在有一个MyService,其中有一个方法是performTask,我们只需要定义一个新的类,实现MethodInterceptor 接口,然后再里面的 intercept 方法实现需要增强的方法。最终通过 cglib 的enhancer 类,先设置父类,父类就是我们要增强的类(也就是被代理类),再设置 callback 也就是我们要增强的功能。最后使用 create 就生成了 cglib 的一个代理类。

题目解析

和 jdk 的动态代理异曲同工,相比 jdk 反而 cglib 的更常考一点。大家理解一下下面的代码流程就很容易说出其中的过程。

面试得分点

目标类,方法拦截器,创建代理对象

题目详细答案

CGLIB是一种强大的代码生成库,能够在运行时生成代理类。与 JDK 动态代理不同的是,CGLIB 不需要接口,可以直接代理具体类。CGLIB 通过创建目标类的子类并覆盖其中的方法来实现代理。

实现步骤

1、 引入 CGLIB 库:确保在项目中添加 CGLIB 依赖。

2、 创建目标类:定义需要代理的具体类。

3、 创建方法拦截器:实现MethodInterceptor接口,并在intercept方法中定义代理逻辑。

4、 创建代理对象:通过Enhancer类创建代理对象。

代码 Demo

假设我们有一个简单的服务类MyService,通过 CGLIB 动态代理为MyService创建一个代理对象,并在方法调用前后添加日志。

引入 CGLIB 依赖
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version>
</dependency>
创建目标类
public class MyService {public void performTask() {System.out.println("Performing task");}
}
创建方法拦截器
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class LoggingMethodInterceptor implements MethodInterceptor {@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("Logging before method execution: " + method.getName());Object result = proxy.invokeSuper(obj, args);System.out.println("Logging after method execution: " + method.getName());return result;}
}
创建代理对象并使用
import net.sf.cglib.proxy.Enhancer;public class MainApp {public static void main(String[] args) {// 创建 Enhancer 对象Enhancer enhancer = new Enhancer();// 设置目标类为代理类的父类enhancer.setSuperclass(MyService.class);// 设置方法拦截器enhancer.setCallback(new LoggingMethodInterceptor());// 创建代理对象MyService proxyInstance = (MyService) enhancer.create();// 调用代理对象的方法proxyInstance.performTask();}
}

详细解释

引入 CGLIB 库:在项目中添加 CGLIB 依赖,以便使用 CGLIB 提供的类和接口。

目标类:MyService是一个具体类,定义了一个方法performTask。

方法拦截器:LoggingMethodInterceptor实现了MethodInterceptor接口。它的intercept方法在代理对象的方法调用时被调用。

intercept方法接收四个参数:obj:代理对象。method:被调用的方法。args:方法参数。proxy:用于调用父类方法的代理对象。

在intercept方法中,我们在方法调用前后添加了日志打印,并通过proxy.invokeSuper调用父类的方法。

创建代理对象:使用Enhancer类创建代理对象。setSuperclass方法设置目标类为代理类的父类。setCallback方法设置方法拦截器。create方法创建代理对象。

使用代理对象

通过代理对象调用方法时,实际调用的是LoggingMethodInterceptor的intercept方法。

在intercept方法中,首先打印日志,然后通过proxy.invokeSuper调用目标对象的方法,最后再打印日志。

CGLIB动态代理通俗解析

面试官您好,关于CGLIB动态代理,我用一个更形象的例子来解释:

魔术师学徒的比喻

想象你是个魔术师(目标类),但想增加些新把戏:

  1. 你本人(MyService):只会基础魔术
  2. 学徒(代理类):继承你的所有技能
  3. 魔术秘籍(MethodInterceptor):教学徒在原有魔术前后添加新动作

实现步骤详解

1. 创建目标类(魔术师本人)

public class Magician {public void performTrick() {System.out.println("从帽子里变出兔子");}public final void secretMove() {System.out.println("这是独门绝技");}
}

2. 编写魔术秘籍(拦截器)

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;public class MagicEnhancer implements MethodInterceptor {@Overridepublic 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;}
}

3. 培养学徒(生成代理)

import net.sf.cglib.proxy.Enhancer;public class MagicShow {public static void main(String[] args) {// 创建增强器(魔术培训班)Enhancer enhancer = new Enhancer();// 指定师父(设置父类)enhancer.setSuperclass(Magician.class);// 传授秘籍(设置回调)enhancer.setCallback(new MagicEnhancer());// 培养出学徒(创建代理)Magician apprentice = (Magician) enhancer.create();// 学徒表演apprentice.performTrick();// 尝试调用final方法// apprentice.secretMove(); // 会报错,无法代理final方法}
}

输出结果

【开场】撒魔术粉
从帽子里变出兔子
【退场】鞠躬致谢

关键点说明

  1. 不需要接口:可以直接对普通类进行代理
  2. 继承机制:通过生成子类来覆盖方法
  3. MethodProxy:比JDK的Method调用效率更高
  4. 限制
    • 无法代理final方法(如上例的secretMove)
    • 无法代理private方法

与JDK代理对比

特性

CGLIB

JDK动态代理

原理

生成子类继承目标类

实现相同接口

速度

方法调用更快

反射调用稍慢

内存

需要生成类字节码,占用更多内存

占用较少

限制

不能代理final方法

必须实现接口

实际项目经验

在Spring项目中:

  1. Controller层通常用CGLIB代理(因为经常没有接口)
  2. 事务管理(@Transactional)底层用CGLIB
  3. 缓存(@Cacheable)也是基于CGLIB

优化建议:

// 可以设置不生成不必要的字段
enhancer.setStrategy(new DefaultGeneratorStrategy() {@Overrideprotected ClassGenerator transform(ClassGenerator cg) {return new TransformingClassGenerator(cg, new AddPropertyTransformer(new String[]{"final"}, new Class[]{boolean.class}));}
});

这样设计既保留了原有类的功能,又能灵活添加新特性,是Spring AOP的重要实现基础。

http://www.dtcms.com/a/317156.html

相关文章:

  • 新能源汽车热管理系统核心零部件及工作原理详解
  • AI巨模型对决2025:五强争霸,谁能称王?
  • ORACLE 19C建库时卡在46%、36%
  • 【网络运维】Linux:简单DHCP服务器的部署
  • PyTorch入门引导
  • 识别 Base64 编码的 JSON、凭证和私钥
  • 接口自动化测试用例详解
  • 使用python与streamlit构建的空间微生物分析
  • RabbitMQ 全面指南:从基础概念到高级特性实现
  • 控制服务和守护进程-systemctl
  • python学智能算法(三十四)|SVM-KKT条件回顾
  • 系统的缓存(buff/cache)是如何影响系统性能的?
  • 【学习笔记之redis】删除缓存
  • 【Redis】hash哈希,List列表
  • app-3
  • Python day36
  • Java Stream API 详解(Java 8+)
  • IP与MAC地址的区别解析
  • 数据仓库命名规范
  • AS32S601 芯片 ADC 模块交流耦合测试:技术要点与实践
  • 使用 gptqmodel 量化 Qwen3-Coder-30B-A3B-Instruct
  • 大型音频语言模型论文总结
  • 【前端开发】三. JS运算符
  • MCU程序段的分类
  • 异世界历险之数据结构世界(非递归快排,归并排序(递归,非递归))
  • 搭建私有 Linux 镜像仓库
  • 算法训练营DAY55 第十一章:图论part05
  • 图论(邻接表)DFS
  • 藏文识别技术:为藏文化的保护、传播、研究与发展注入核心动力
  • 【C++基础】宏的高级替代方案:面试高频考点 + 真题解析全攻略