cglib中proxy动态代理解析

来源:互联网 发布:淘宝平拍裤子褶皱手法 编辑:程序博客网 时间:2024/06/07 08:31

CGLIB中的动态代理是JDK proxy的一个很好的补充,在JDK中实现代理时,要求代理类必须是继承接口的类,因为JDK最后生成的proxy class其实就是实现了被代理类所继承的接口并且继承了java中的Proxy类,通过反射找到接口的方法,调用InvocationHandler的invoke 方法实现拦截。CGLIb中最后生成的proxy class是一个继承被代理类的class,通过重写被代理类中的非final的方法实现代理。总结为:
JDK proxy:代理类必须实现接口
CGLIB: 代理类不能是final,代理的方法也不能是final(继承限制)
关于JDK proxy原理,可参看之前的整理
http://blog.csdn.net/sunnycoco05/article/details/78845878
下面看看CGLIb中的处理,我们要实现对一个类进行代理,在调用方法前后进行简单处理
创建一个要代理的类:
有一个printName类方法

public class MyTarget {    public void printName() {        System.err.println("name:Target-");    }

自己的拦截器,CGLIb中实现MethodInterceptor接口,它可支持对不同方法的拦截,这里我们统一处理:

public class MyInterceptor implements MethodInterceptor {    @Override    public Object intercept(Object obj, Method method, Object[] params, MethodProxy proxy) throws Throwable {        System.err.println("=======before======");        Object res = proxy.invokeSuper(obj, params);        System.err.println("=======and======");        return res;    }}

只是在方法调用前后进行简单打印。CGLIb中通过Enhancer类进行代理操作,开始测试:

@Test    public void proxyTest() {        Enhancer enhancer = new Enhancer();        enhancer.setSuperclass(MyTarget.class);        enhancer.setCallback(new MyInterceptor());        MyTarget target = (MyTarget) enhancer.create();        target.printName();        System.out.println("proxy class name:" + target.getClass().getName());    }

运行结果:
这里写图片描述

成功实现拦截。
动态代理,其实就是动态的生成一个有关被代理类的class文件,并加装运行这个class文件的过程。如果我们可以把JVM中生成的class 文件保存下来,再通过反编译后的Java文件去分析,应该就很清楚的去看懂它的原理。我们可以用-javaagent去实现这个功能。自定义一个agent 类, 这个Agent在class文件装载的时候,我们判断是否是生成的代理类(根据class name判断),如果符合,将class的字节流写入文件,存在指定位置

public class MyAgent implements ClassFileTransformer {    //会在main方法之前执行,添加自定义的的ClassFileTransformer    public static void premain(String agentArgs, Instrumentation inst) {        inst.addTransformer(new MyAgent());    }    //每次装载class文件都会执行    @Override    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {        //com.cglib.MyTarget$$EnhancerByCGLIB$$65288428        //com.sun.proxy.$Proxy4        //CGLIB和JDK proxy生成的代理类进行拦截        if (className.contains("$$EnhancerByCGLIB$$") || className.contains("$Proxy")) {            //指定存放路径            String path = "yourdirpath";            int lastIndexOf = className.lastIndexOf("/") + 1;            String classFileName = className.substring(lastIndexOf) + ".class";            writeClassToDisk(path + classFileName, classfileBuffer);            System.out.println(className + "---writeClassToDisk Succeess!");        }        return classfileBuffer;    }    //将class文件存在磁盘    private void writeClassToDisk(String fileName, byte[] data) {        try {            File file = new File(fileName);            if (!file.exists()) {                file.createNewFile();            }            FileOutputStream fos = new FileOutputStream(file);            fos.write(data);            fos.close();        } catch (Exception e) {            e.printStackTrace();        }    }}

将MyAgent打成jar包myagent.jar 。在eclipse中的export功能中,选择工程中存在的MANIFEST.MF文件进行打包,MANIFEST.MF文件内容为:

Manifest-Version: 1.0Premain-Class: com.cglib.MyAgent

表示版本号和Premain-Class所在的class文件
将 jar包放入项目路径下。
测试类:

public class AgentTest {    //main方法中运行    public static void main(String[] args) {        Enhancer enhancer = new Enhancer();        enhancer.setSuperclass(MyTarget.class);        enhancer.setCallback(new MyInterceptor());        MyTarget myTarget = (MyTarget) enhancer.create();         myTarget.printName();        System.err.println("proxy name: " + myTarget.getClass().getName());    }}

字eclipse中,右键->Run As >Run configurations,在Arguments中添加:-javaagent:myagent.jar
这里写图片描述
运行:
这里写图片描述
从命名可以看到,MyTarget$$EnhancerByCGLIB$$b0fb28f5就是我们要找的MyTarget类的代理类,而运行中又加载了一个com/cglib/MyTarget$$EnhancerByCGLIB$$b0fb28f5$$FastClassByCGLIB$$1a454ece的class文件。
现在我们已经把cglib生成的class文件保留了,反编译查看代码:

package com.cglib;import com.cglib.MyTarget;import java.lang.reflect.Method;import net.sf.cglib.core.ReflectUtils;import net.sf.cglib.core.Signature;import net.sf.cglib.proxy.Callback;import net.sf.cglib.proxy.Factory;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;//继承了MyTarget实现了Factory接口public class MyTarget$$EnhancerByCGLIB$$b0fb28f5 extends MyTarget implements Factory {    private boolean CGLIB$BOUND;    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;    private static final Callback[] CGLIB$STATIC_CALLBACKS;    private MethodInterceptor CGLIB$CALLBACK_0;    private static final Method CGLIB$printName$0$Method;    private static final MethodProxy CGLIB$printName$0$Proxy;    private static final Object[] CGLIB$emptyArgs;    private static final Method CGLIB$finalize$1$Method;    private static final MethodProxy CGLIB$finalize$1$Proxy;    private static final Method CGLIB$equals$2$Method;    private static final MethodProxy CGLIB$equals$2$Proxy;    private static final Method CGLIB$toString$3$Method;    private static final MethodProxy CGLIB$toString$3$Proxy;    private static final Method CGLIB$hashCode$4$Method;    private static final MethodProxy CGLIB$hashCode$4$Proxy;    private static final Method CGLIB$clone$5$Method;    private static final MethodProxy CGLIB$clone$5$Proxy;    //初始化一堆方法参数组等    static void CGLIB$STATICHOOK1() {        CGLIB$THREAD_CALLBACKS = new ThreadLocal();        CGLIB$emptyArgs = new Object[0];        Class arg = Class.forName("com.cglib.MyTarget$$EnhancerByCGLIB$$b0fb28f5");        Class arg0;        Method[] arg9999 = ReflectUtils.findMethods(                new String[]{"finalize", "()V", "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;",                        "hashCode", "()I", "clone", "()Ljava/lang/Object;"},                (arg0 = Class.forName("java.lang.Object")).getDeclaredMethods());        CGLIB$finalize$1$Method = arg9999[0];        CGLIB$finalize$1$Proxy = MethodProxy.create(arg0, arg, "()V", "finalize", "CGLIB$finalize$1");        CGLIB$equals$2$Method = arg9999[1];        CGLIB$equals$2$Proxy = MethodProxy.create(arg0, arg, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$2");        CGLIB$toString$3$Method = arg9999[2];        CGLIB$toString$3$Proxy = MethodProxy.create(arg0, arg, "()Ljava/lang/String;", "toString", "CGLIB$toString$3");        CGLIB$hashCode$4$Method = arg9999[3];        CGLIB$hashCode$4$Proxy = MethodProxy.create(arg0, arg, "()I", "hashCode", "CGLIB$hashCode$4");        CGLIB$clone$5$Method = arg9999[4];        CGLIB$clone$5$Proxy = MethodProxy.create(arg0, arg, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5");        CGLIB$printName$0$Method = ReflectUtils.findMethods(new String[]{"printName", "()V"},                (arg0 = Class.forName("com.cglib.MyTarget")).getDeclaredMethods())[0];        CGLIB$printName$0$Proxy = MethodProxy.create(arg0, arg, "()V", "printName", "CGLIB$printName$0");    }    final void CGLIB$printName$0() {        super.printName();    }    //重写MyTarget的printName方法    public final void printName() {        MethodInterceptor arg9999 = this.CGLIB$CALLBACK_0;        if (this.CGLIB$CALLBACK_0 == null) {            CGLIB$BIND_CALLBACKS(this);            arg9999 = this.CGLIB$CALLBACK_0;        }        if (arg9999 != null) {            arg9999.intercept(this, CGLIB$printName$0$Method, CGLIB$emptyArgs, CGLIB$printName$0$Proxy);        } else {            super.printName();        }    }    final void CGLIB$finalize$1() throws Throwable {        super.finalize();    }    protected final void finalize() throws Throwable {        MethodInterceptor arg9999 = this.CGLIB$CALLBACK_0;        if (this.CGLIB$CALLBACK_0 == null) {            CGLIB$BIND_CALLBACKS(this);            arg9999 = this.CGLIB$CALLBACK_0;        }        if (arg9999 != null) {            arg9999.intercept(this, CGLIB$finalize$1$Method, CGLIB$emptyArgs, CGLIB$finalize$1$Proxy);        } else {            super.finalize();        }    }    final boolean CGLIB$equals$2(Object arg0) {        return super.equals(arg0);    }    public final boolean equals(Object arg0) {        MethodInterceptor arg9999 = this.CGLIB$CALLBACK_0;        if (this.CGLIB$CALLBACK_0 == null) {            CGLIB$BIND_CALLBACKS(this);            arg9999 = this.CGLIB$CALLBACK_0;        }        if (arg9999 != null) {            Object arg1 = arg9999.intercept(this, CGLIB$equals$2$Method, new Object[]{arg0}, CGLIB$equals$2$Proxy);            return arg1 == null ? false : ((Boolean) arg1).booleanValue();        } else {            return super.equals(arg0);        }    }    final String CGLIB$toString$3() {        return super.toString();    }    public final String toString() {        MethodInterceptor arg9999 = this.CGLIB$CALLBACK_0;        if (this.CGLIB$CALLBACK_0 == null) {            CGLIB$BIND_CALLBACKS(this);            arg9999 = this.CGLIB$CALLBACK_0;        }        return arg9999 != null                ? (String) arg9999.intercept(this, CGLIB$toString$3$Method, CGLIB$emptyArgs, CGLIB$toString$3$Proxy)                : super.toString();    }    final int CGLIB$hashCode$4() {        return super.hashCode();    }    public final int hashCode() {        MethodInterceptor arg9999 = this.CGLIB$CALLBACK_0;        if (this.CGLIB$CALLBACK_0 == null) {            CGLIB$BIND_CALLBACKS(this);            arg9999 = this.CGLIB$CALLBACK_0;        }        if (arg9999 != null) {            Object arg0 = arg9999.intercept(this, CGLIB$hashCode$4$Method, CGLIB$emptyArgs, CGLIB$hashCode$4$Proxy);            return arg0 == null ? 0 : ((Number) arg0).intValue();        } else {            return super.hashCode();        }    }    final Object CGLIB$clone$5() throws CloneNotSupportedException {        return super.clone();    }    protected final Object clone() throws CloneNotSupportedException {        MethodInterceptor arg9999 = this.CGLIB$CALLBACK_0;        if (this.CGLIB$CALLBACK_0 == null) {            CGLIB$BIND_CALLBACKS(this);            arg9999 = this.CGLIB$CALLBACK_0;        }        return arg9999 != null                ? arg9999.intercept(this, CGLIB$clone$5$Method, CGLIB$emptyArgs, CGLIB$clone$5$Proxy)                : super.clone();    }    public static MethodProxy CGLIB$findMethodProxy(Signature arg) {        String arg9999 = arg.toString();        switch (arg9999.hashCode()) {            case -1574182249 :                if (arg9999.equals("finalize()V")) {                    return CGLIB$finalize$1$Proxy;                }                break;            case -508378822 :                if (arg9999.equals("clone()Ljava/lang/Object;")) {                    return CGLIB$clone$5$Proxy;                }                break;            case 1826985398 :                if (arg9999.equals("equals(Ljava/lang/Object;)Z")) {                    return CGLIB$equals$2$Proxy;                }                break;            case 1861880221 :                if (arg9999.equals("printName()V")) {                    return CGLIB$printName$0$Proxy;                }                break;            case 1913648695 :                if (arg9999.equals("toString()Ljava/lang/String;")) {                    return CGLIB$toString$3$Proxy;                }                break;            case 1984935277 :                if (arg9999.equals("hashCode()I")) {                    return CGLIB$hashCode$4$Proxy;                }        }        return null;    }    public MyTarget$$EnhancerByCGLIB$$b0fb28f5() {        CGLIB$BIND_CALLBACKS(this);    }    public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] arg) {        CGLIB$THREAD_CALLBACKS.set(arg);    }    public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] arg) {        CGLIB$STATIC_CALLBACKS = arg;    }    private static final void CGLIB$BIND_CALLBACKS(Object arg) {        MyTarget$$EnhancerByCGLIB$$b0fb28f5 arg0 = (MyTarget$$EnhancerByCGLIB$$b0fb28f5) arg;        if (!arg0.CGLIB$BOUND) {            arg0.CGLIB$BOUND = true;            Object arg9999 = CGLIB$THREAD_CALLBACKS.get();            if (arg9999 == null) {                arg9999 = CGLIB$STATIC_CALLBACKS;                if (CGLIB$STATIC_CALLBACKS == null) {                    return;                }            }            arg0.CGLIB$CALLBACK_0 = (MethodInterceptor) ((Callback[]) arg9999)[0];        }    }    public Object newInstance(Callback[] arg0) {        CGLIB$SET_THREAD_CALLBACKS(arg0);        MyTarget$$EnhancerByCGLIB$$b0fb28f5 arg9999 = new MyTarget$$EnhancerByCGLIB$$b0fb28f5();        CGLIB$SET_THREAD_CALLBACKS((Callback[]) null);        return arg9999;    }    public Object newInstance(Callback arg0) {        CGLIB$SET_THREAD_CALLBACKS(new Callback[]{arg0});        MyTarget$$EnhancerByCGLIB$$b0fb28f5 arg9999 = new MyTarget$$EnhancerByCGLIB$$b0fb28f5();        CGLIB$SET_THREAD_CALLBACKS((Callback[]) null);        return arg9999;    }    public Object newInstance(Class[] arg0, Object[] arg1, Callback[] arg2) {        // $FF: Couldn't be decompiled    }    public Callback getCallback(int arg0) {        CGLIB$BIND_CALLBACKS(this);        MethodInterceptor arg9999;        switch (arg0) {            case 0 :                arg9999 = this.CGLIB$CALLBACK_0;                break;            default :                arg9999 = null;        }        return arg9999;    }    public void setCallback(int arg0, Callback arg1) {        switch (arg0) {            case 0 :                this.CGLIB$CALLBACK_0 = (MethodInterceptor) arg1;            default :        }    }    public Callback[] getCallbacks() {        CGLIB$BIND_CALLBACKS(this);        return new Callback[]{this.CGLIB$CALLBACK_0};    }    public void setCallbacks(Callback[] arg0) {        this.CGLIB$CALLBACK_0 = (MethodInterceptor) arg0[0];    }    static {        CGLIB$STATICHOOK1();    }}

CGLIB生成的class文件中,部分不能被反编译,但对我们理解它的代理原理起到很大作用了。从中我们看到,继承了MyTaget通过重写定义方法啦实现代理,也就说明CGLIB不能用作代理final标识的类和方法。在调用printName方法时,最终调用传入的MethodInterceptor实例的intercept方法,也就是我们的MyInterceptor。具体的传入和逻辑可根据源码分析

原创粉丝点击