CGLib动态代理使用与原理的简单分析

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写入本地的判断,所以我们调试时可以这么写:

你可能感兴趣的:(java)