CGLIB 库是一个强大的、高性能、高品质的Code生成库,用于在运行时扩展Java类与实现Java接口。CGLib代理的主要用途是针对类创建一个子类、在运行时扩充对象行为;而JDK动态代理则是针对接口实现代理。使用CGLib时,不必要求目标对象必须实现接口。CGLib由于是在运行时生成类的子类来实现,因此被称为子类代理。它的使用涉及到创建增强器、设置回调处理器以及生成代理等步骤。
一、CGLIB代理概述
CGLIB代理的使用广泛应用在诸如Spring框架中用于实现AOP(面向切面编程)功能。它通过底层的字节码技术,为一个类创建一个子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,并判断是否进行增强。
二、实现CGLIB代理的步骤
创建一个类需要被代理的类,称它为BaseClass。
public class BaseClass {
public void doSomething(){
System.out.println("Doing something");
}
}
定义一个MethodInterceptor这是CGLib在调用代理对象中拦截到被代理方法时候,所要执行的方法拦截器。
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class BaseClassInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before method execute");
Object result = proxy.invokeSuper(obj, args);
System.out.println("After method execute");
return result;
}
}
生成CGLIB代理对象通过Enhancer类可以创建CGLIB代理对象,增强器enhancer.setSuperclass
用于设置生成类的父类,enhancer.setCallback
用于设置回调,调用enhancer.create
生成代理对象。
import net.sf.cglib.proxy.Enhancer;
public class CglibProxyCreator {
public static BaseClass createProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(BaseClass.class);
enhancer.setCallback(new BaseClassInterceptor());
return (BaseClass) enhancer.create();
}
}
三、CGLIB代理的高级特性
CGLIB不仅仅能够实现简单的代理,在实践中,通常会结合各种高级特性来完成复杂的需求。
方法过滤CGLIB提供了CallbackFilter接口,可以用于在生成代理对象时,对不同的方法应用不同的回调逻辑。
import net.sf.cglib.proxy.CallbackFilter;
import java.lang.reflect.Method;
public class BaseClassCallbackFilter implements CallbackFilter {
@Override
public int accept(Method method) {
if ("doSomething".equals(method.getName())) {
return 0; // 使用索引为0的回调
}
return 1; // 使用索引为1的回调
}
}
通过这个CallbackFilter,我们可以控制不同方法执行不同的回调逻辑。
多个回调CGLIB支持使用多个回调并结合CallbackFilter使用。
enhancer.setCallbacks(new Callback[]{new BaseClassInterceptor(), NoOp.INSTANCE});
enhancer.setCallbackFilter(new BaseClassCallbackFilter());
在上述代码中,NoOp.INSTANCE是CGLIB提供的一个Callback,它会直接放行该方法的调用,不会做任何处理。
有状态的和无状态的回调有状态的回调Callback会在多次调用中保留状态信息,而无状态的则不会。MethodInterceptor是有状态的,每次代理对象的方法被调用都会进入相同的MethodInterceptor实现。
四、CGLIB代理的性能
相对于JDK动态代理,CGLIB通常会有更好的执行性能,原因在于CGLIB生成的是真正的类而非接口的实现。在Java的动态代理上,每次调用代理对象的方法时,都会转发到InvocationHandler的invoke方法,而CGLIB则通过直接扩展类并在子类中添加了方法拦截逻辑来实现。然而,由于需要动态生成字节码,在创建代理对象的时候CGLIB的开销会比较大。
五、CGLIB代理的局限性
无法代理final方法由于CGLIB是通过继承的方式生成代理对象,Java语言规范禁止父类的final方法被子类覆盖。因此在CGLIB代理中,被final修饰的方法无法进行拦截和增强。
针对构造器的限制CGLIB在创建子类时,会自动调用超类(即被代理类)的无参数构造器。如果原始类没有提供无参数的构造器,就需要在子类中手工编码调用其他的构造器。如果原始类的构造器具有副作用或者执行成本较高,这将会是一个问题。
综上所述,CGLIB提供了一种强大的方式来创建运行时代理,特别适用于无法修改代码或者无法实现接口的情况下。与JDK动态代理相比,CGLIB在运行时性能上更有优势,但其初始化成本更高,且不支持final方法以及具有某些构造器限制。在实际使用中,选择CGLIB还是JDK动态代理,要根据具体需求进行考量。
相关问答FAQs:
Cglib代理是什么?它与Java动态代理的区别是什么?
Cglib代理是一种基于字节码的代理机制,它通过创建目标类的子类来实现代理。与Java动态代理不同,它可以代理非接口类型的类。
如何使用Cglib代理?
要使用Cglib代理,首先需要引入Cglib库,然后创建一个Enhancer对象。通过调用Enhancer对象的setSuperclass()方法设置目标类,调用setCallback()方法设置回调处理器,最后调用create()方法创建代理对象。
Cglib代理的优缺点是什么?
Cglib代理的优点是它可以代理非接口类型的类,相比于Java动态代理更加灵活。它还能够实现对目标类方法细粒度的代理控制。
然而,Cglib代理的缺点是它在创建代理对象时的性能相对较低,因为它涉及到对字节码的操作。此外,Cglib代理不能代理被final关键字修饰的方法。
请注意,在使用Cglib代理时,目标类和被代理的方法不能是final修饰的。