CGLIB动态代理机制

CGLIB原理

cglib是一个java字节码的生成工具,它动态生成一个被代理类的子类,子类重写被代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。

示例

被代理类:

public class HelloServiceImpl {
    public void sayHello(){
        System.out.println("Hello Zhanghao");
    }

    public void sayBey(){
        System.out.println("Bye Zhanghao");
    }
}

实现MethodInterceptor接口生成方法拦截器:

public class HelloMethodInterceptor  implements MethodInterceptor{
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("Before: "  + method.getName());
        Object object = methodProxy.invokeSuper(o, objects);
        System.out.println("After: " + method.getName());
        return object;
    }
}

生成代理类对象并打印在代理类对象调用方法之后的执行结果:

public class Client {
    public static void main(String[] args) {
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/Users/zhanghao/Documents/toy/spring-framework-source-study/");
        Enhancer enhancer = new Enhancer();
        //继承被代理类
        enhancer.setSuperclass(HelloServiceImpl.class);
        //设置回调
        enhancer.setCallback(new HelloMethodInterceptor());
        //设置代理类对象
        HelloServiceImpl helloService = (HelloServiceImpl) enhancer.create();
        //在调用代理类中方法时会被我们实现的方法拦截器进行拦截
        helloService.sayBey();
    }
}
result:
Before: sayBey
Bye Zhanghao
After: sayBey

构建代理类过程

我们可以从上面的代码示例中看到,代理类是由enhancer.create()创建的。Enhancer是CGLIB的字节码增强器,可以很方便的对类进行拓展。

创建代理类的过程:

  • 生成代理类的二进制字节码文件;
  • 加载二进制字节码,生成Class对象;
  • 通过反射机制获得实例构造,并创建代理类对象。

enhancer.create()实现:

/**
     * Generate a new class if necessary and uses the specified
     * callbacks (if any) to create a new object instance.
     * Uses the no-arg constructor of the superclass.
     * @return a new instance
     */
    public Object create() {
        classOnly = false;
        argumentTypes = null;
        return createHelper();
    }
    
     private Object createHelper() {
        validate();
        if (superclass != null) {
            //设置生成类的名称
            setNamePrefix(superclass.getName());
        } else if (interfaces != null) {
            //设置生成类的名称
            setNamePrefix(interfaces[ReflectUtils.findPackageProtected(interfaces)].getName());
        }
        //生成代理类对象(在KEY_FACTORY.newInstance(...)->生成代理类的二进制字节码文件以及加载二进制字节码)
        return super.create(KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
                                                    ReflectUtils.getNames(interfaces),
                                                    filter,
                                                    callbackTypes,
                                                    useFactory,
                                                    interceptDuringConstruction,
                                                    serialVersionUID));
    }

cglic一共会自动生成三个字节码文件。其中一个类HelloServiceImpld855d4dc 继承了被代理类 HelloServiceImpl。这个类就是加强的代理类,其中会生成两个方法CGLIB1()sayHello()
其中sayHello():

  public final void sayHello() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if(this.CGLIB$CALLBACK_0 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if(var10000 != null) {
            var10000.intercept(this, CGLIB$sayHello$1$Method, CGLIB$emptyArgs, CGLIB$sayHello$1$Proxy);
        } else {
            super.sayHello();
        }
    }

当代理对象的执行sayHello方法时,会首先判断一下是否存在实现了MethodInterceptor接口的CGLIB$CALLBACK_0;,如果存在,则将调用MethodInterceptor中的intercept方法。

与JDK代理对比

JDK代理要求被代理的类必须实现接口,有很强的局限性。而CGLIB动态代理则没有此类强制性要求。简单的说,CGLIB会让生成的代理类继承被代理类,并在代理类中对代理方法进行强化处理(前置处理、后置处理等)。但是如果被代理类被final修饰,那么它不可被继承,即不可被代理;同样,如果被代理类中存在final修饰的方法,那么该方法也不可被代理。

你可能感兴趣的:(CGLIB动态代理机制)