Cglib是什么
Cglib是一个强大的,高性能,高质量的代码生成类库。它可以在运行期扩展JAVA类与实现JAVA接口。其底层实现是通过ASM字节码处理框架来转换字节码并生成新的类。大部分功能实际上是ASM所提供的,Cglib只是封装了ASM,简化了ASM操作,实现了运行期生成新的class。
Cglib的原理
运行时动态的生成一个被代理类的子类(通过ASM字节码处理框架实现),子类重写了被代理类中所有非final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势植入横切逻辑。
Cglib优缺点
- 优点:JDK动态代理要求被代理的类必须实现接口,当需要代理的类没有实现接口时Cglib代理是一个很好的选择。另一个优点是Cglib动态代理比使用java反射的JDK动态代理要快
- 缺点:对于被代理类中的final方法,无法进行代理,因为子类中无法重写final函数
Cglib类库
- net.sf.cglib.core:底层字节码处理类,他们大部分与ASM有关系。
- net.sf.cglib.transform:编译期或运行期类和类文件的转换。
- net.sf.cglib.proxy:实现创建代理和方法拦截器的类。
- net.sf.cglib.reflect:实现快速反射和C#风格代理的类。
- net.sf.cglib.util:集合排序等工具类。
- net.sf.cglib.beans:JavaBean相关的工具类。
下面是它的简单的一个使用示例(本文使用的还是cglib-nodep-2.2.2.jar):
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.InvocationHandler;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CGLib {
public static class Human {
void doThings() {
System.out.println("fuck you");
}
}
public static class CglibProxyA implements MethodInterceptor {
public Object getProxyInstance(Object target) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("before target method...");
Object result = methodProxy.invokeSuper(o, objects);
System.out.println("after target method...");
return result;
}
}
public static class CglibProxyB implements InvocationHandler {
private Object target;
public Object getProxyInstance(Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
System.out.println("before target method...");
Object result = method.invoke(target, objects);
System.out.println("after target method...");
return result;
}
}
public static void main(String[] args) {
((Human) new CglibProxyA().getProxyInstance(new Human())).doThings();
((Human) new CglibProxyB().getProxyInstance(new Human())).doThings();
}
}
可以看到,相对JDK的动态代理,cglib的动态代理使用更简单,关键是,它不需要接口,任何一个类都可以被轻松的代理(final类不能,final方法也不能)。
- JDK动态代理的拦截对象是通过反射的机制来调用被拦截方法的,反射的效率比较低,所以cglib采用了FastClass的机制来实现对被拦截方法的调用。FastClass机制就是对一个类的方法建立索引,通过索引来直接调用相应的方法。
- DefaultGeneratorStrategy中使用了DebuggingClassWriter,这个类中有判断是否将class写入本地的判断,所以我们调试时可以这么写: