cglib学习(一)

原文:http://hnicypb.javaeye.com/blog/263841http://xujunprogrammer.blog.hexun.com/33636034_d.htmlhttp://blog.youkuaiyun.com/zt2oo8/archive/2006/07/23/963609.aspx

 

 

1.CGLIB包的介绍

代理为控制要访问的目标对象提供了一种途径。当访问对象时,它引入了一个间接的层。JDK自从1.3版本开始,就引入了动态代理,并且经常被用来动态地创建代理。JDK的动态代理用起来非常简单,当它有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的类,该怎么办?现在我们可以使用CGLIB包。

 CGLIB是一个强大的高性能的代码生成包。它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)。最流行的OR Mapping工具hibernate也使用CGLIB来代理单端single-ended(多对一和一对一)关联(对集合的延迟抓取,是采用其他机制实现的)。EasyMock和jMock是通过使用模仿(moke)对象来测试java代码的包。它们都通过使用CGLIB来为那些没有接口的类创建模仿(moke)对象。
    CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。除了CGLIB包,脚本语言例如 Groovy和BeanShell,也是使用ASM来生成java的字节码。当不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。

2.学习例子

目标对象

拦截器

测试

 

运行结果

>>>MethodInterceptor start... 
----------test()---------- 
>>>MethodInterceptor ending...


3.相关内容解释

CGLIB包是在ASM之上的一个高级别的层。对代理那些没有实现接口的类非常有用。本质上,它是通过动态的生成一个子类去覆盖所要代理类的不是final的方法,并设置好callback,则原有类的每个方法调用就会转变成调用用户定义的拦截方法(interceptors),这比 JDK动态代理方法快多了。

1)net.sf.cglib.proxy.Callback

net.sf.cglib.proxy.Callback接口在CGLIB包中是一个很关键的接口,所有被net.sf.cglib.proxy.Enhancer类调用的回调(callback)接口都要继承这个接口。 net.sf.cglib.proxy.MethodInterceptor接口是最通用的回调(callback)类型,它经常被基于代理的AOP用来实现拦截(intercept)方法的调用。这个接口只定义了一个方法

  • public Object intercept(Object object, java.lang.reflect.Method method,Object[] args, MethodProxy proxy) throws Throwable;

    当net.sf.cglib.proxy.MethodInterceptor做为所有代理方法的回调(callback)时,当对基于代理的方法调用时,在调用原对象的方法之前会调用这个方法,如下图所示。

第一个参数是代理对像,第二和第三个参数分别是拦截的方法和方法的参数。原来的方法可能通过使用java.lang.reflect.Method对象的一般反射调用,或者使用 net.sf.cglib.proxy.MethodProxy对象调用。net.sf.cglib.proxy.MethodProxy通常被首选使用,因为它更快。在这个方法中,我们可以在调用原方法之前或之后注入自己的代码。

2)net.sf.cglib.proxy.CallbackFilte

代理类的所有方法经常会用到回调(callback),但是你也可以使用net.sf.cglib.proxy.CallbackFilter 有选择的对一些方法使用回调(callback),这种考虑周详的控制特性在JDK的动态代理中是没有的。在JDK代理中,对 java.lang.reflect.InvocationHandler方法的调用对代理类的所有方法都有效。

可参见下述例子:

 

 

 

执行结果:

public void cglib_test.MyClass.method()
MyClass.method()
MyClass.method2()//未进行代理。
3)net.sf.cglib.proxy.Mixin
CGLIB的代理包也对net.sf.cglib.proxy.Mixin提供支持。基本上,它允许多个对象被绑定到一个单个的大对象。在代理中对方法的调用委托到相应的对象中。
可参见下述例子:
 
 
执行结果:
MyInterfaceAImpl.methodA()
MyInterfaceBImpl.methodB()

 

<think> 嗯,用户想要全面了解CGLIB,包括介绍、使用方法、原理和应用场景。从对话历史看,用户已经提供了些站内引用资料,这些资料主要集中在CGLIB的工作原理和与JDK动态代理的对比上。 用户可能是位Java开发者,正在学习或使用Spring框架,需要深入理解底层代理机制。ta的提问非常结构化,说明对技术细节有较高要求。考虑到CGLIB在Spring AOP中的核心地位,用户可能实际想解决的是框架使用中的代理相关问题。 从引用材料可以提取几个关键点: 1)CGLIB通过生成目标类的子类实现代理,不要求实现接口(引用1、2) 2)底层基于ASM字节码操作(引用4) 3)比JDK代理更灵活,可控制方法细节(引用3) 4)不能代理final类/方法(引用4) 需要补充用户没提到的使用方法和代码示例,这部分引用材料较欠缺。同时要注意原理部分需要用LaTeX公式说明字节码生成过程,比如方法拦截的数学表达。 用户情绪应该是求知欲较强的状态,提问方式专业,可能正在准备技术方案或面试。回复时需要强调实践代码,原理部分用流程图辅助理解,最后补充应用场景时关联Spring框架的实际使用会更有价值。 </think> 以下是关于CGLIB的详细介绍,包含原理、使用方法及应用场景: --- ### **CGLIB 核心介绍** CGLIB(Code Generation Library)是个基于ASM的字节码生成库,用于在**运行时动态生成被代理类的子类**。与JDK动态代理相比,其核心优势在于**无需目标类实现接口**,可直接代理普通类[^1][^2]。 --- ### **工作原理** 1. **继承机制** CGLIB动态生成目标类的子类(如 `TargetClass$$EnhancerByCGLIB`),重写所有**非final、非static的public方法**。 $$ \text{代理类} = \text{TargetClass} + \text{方法拦截逻辑} $$ 2. **方法拦截** 通过`MethodInterceptor`接口拦截方法调用: ```java public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) { // 前置增强 Object result = proxy.invokeSuper(obj, args); // 调用父类(原目标类)方法 // 后置增强 return result; } ``` 3. **字节码生成** 底层使用ASM直接操作字节码,生成新类的二进制代码,再通过ClassLoader加载[^4]。 --- ### **使用方法(Spring集成示例)** ```java // 1. 创建Enhancer Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(TargetClass.class); // 设置目标类 enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) { System.out.println("Before method: " + method.getName()); Object result = proxy.invokeSuper(obj, args); System.out.println("After method: " + method.getName()); return result; } }); // 2. 创建代理对象 TargetClass proxy = (TargetClass) enhancer.create(); // 3. 调用方法(触发拦截) proxy.doSomething(); ``` --- ### **应用场景** 1. **代理无接口的类** 当目标类未实现任何接口时(如遗留代码),必须使用CGLIB[^1][^3]。 2. **性能敏感场景** CGLIB生成的代理类调用效率更高(JDK代理需反射调用)。 3. **方法级精细控制** 支持修改方法参数、返回值等深度操作[^3]。 4. **框架集成** Spring AOP默认对无接口类使用CGLIB(通过`proxy-target-class=true`强制启用)[^1][^4]。 --- ### **限制与注意事项** | 限制类型 | 说明 | |-------------------|-----------------------------| | **final方法/类** | 无法代理(子类不能重写final方法) | | **构造函数** | 每次创建代理都调用两次目标类构造器 | | **依赖冲突** | 需确保ASM库版本兼容 | --- ### **与JDK动态代理对比** | 特性 | JDK动态代理 | CGLIB | |---------------|--------------------------|------------------------| | **代理对象** | 接口实现类 | 目标类的子类 | | **依赖要求** | 需实现接口 | 无接口要求 | | **性能** | 反射调用稍慢 | 直接方法调用更快 | | **方法范围** | 仅代理接口方法 | 可代理所有非final方法 | > ⚠️ **实践建议**:在Spring中优先选择JDK代理(遵循面向接口编程),仅当目标类无接口时使用CGLIB[^3][^4]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值