代理模式(JDK和CGLib)

本文聚焦Java代理模式,介绍其应用场景与原理,指出代理模式用于控制对象访问、保护和增强对象。详细阐述静态代理和动态代理区别,动态代理又分JDK和CGLib实现,还探究JDK动态代理原理并手写实现,最后总结CGLib和JDK Proxy的根本区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

掌握代理模式的应用场景和实现原理

生活中常见的常见,如租房中介,黄牛,婚介,猎头等

代码中常见的应用有事务代理,非侵入式的日志监听等.

代理模式(Proxy Pattern)的定义就是为一般对象提供代理(访问先经过代理对象再到被代理对象),用以控制对这个对象的访问.

代理模式属于结构型设计模式,使用目的就是为了保护对象和增强对象
下面是一个静态代理模式实现的类图.

客户调用的时候调用的是proxy类对象,代理类持有被代理类对象引用,使用的时候只需要传递请求数据给代理类,代理类会进行日志记录,然后让被代理类执行请求逻辑
在这里插入图片描述

在代码中,我们想到代理,就会理解为是代码 增强,其实就是在原本逻辑前后增加一些逻辑,而调用者无感知。代理模式属于结构型 模式,有静态代理和动态代理

了解静态代理和动态代理的区别。

静态代理

代理

public class ProxyLog {
    private RealRequest proxy;

    public ProxyLog(RealRequest requestProxy) {
        this.proxy = requestProxy;
    }

    public void log() {
        System.out.println("访问请求方法");
    }

    public void request(String data) {
        log();
        proxy.request(data);
    }
}
public class RealRequest {

    public void request(String data) {
        System.out.println("data:" + data);
    }
}
    public static void main(String[] args) {
        String data = "hello world";
        ProxyLog proxyLog = new ProxyLog(new RealRequest());
        proxyLog.request(data);
    }

动态代理

动态代理和静态代理的思路基本一致,都是根据被代理对象,在调用被代理对象前做一些处理.
不同的是代理对象的功能更加强大,从上面的静态代理可以看出局限很大,只能代理指定对象的指定方法.

JDK实现动态代理

下面是一个JDK实现动态代理的例子

//JDK动态代理转换类,根据接口转换
public interface CustomRequest {
    public void request();
    public void setHeader();
}
public class RealRequest implements CustomRequest {

    @Override
    public void setHeader() {
        System.out.println("setHeader");
    }

    @Override
    public void request() {
        System.out.println("hello");
    }
}
public class ProxyLog implements InvocationHandler {
    private Object target;


    public Object getInstance(Object target) throws Exception {
        this.target = target;
        Class<?> clazz = target.getClass();
        //根据clazz.getInterfaces()获得的接口,得到可以转换的类型和调用方法,无法直接转换为clazz
        return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
    }

    /*   proxy为根据ProxyLog实现的invoke方法生成的代理对象
       也就是通过Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this)
       返回的对象
       ((ProxyLog) ((Proxy) proxy).h).target==target
       method是当前代理对象调用的方法,args是当前调用方法
       传递的参数,result为方法调用的返回值Void方法返回null*/
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log(method.getName());
        Object result = method.invoke(target, args);
        return result;
    }

    public void log(String methodName) {
        System.out.println("invoke:" + methodName);
    }
}
    public static void main(String[] args) throws Exception {
        CustomRequest request = ((CustomRequest) new ProxyLog().getInstance(new RealRequest()));
        request.request();
        request.setHeader();
    }

动态代理之后,不止是RealRequest类的request(),任何实现了CustomRequest接口的类调用的由接口定义的方法和Object的方法都可以被代理(具体查看手写实现定义的动态代理部分).

CGLib 实现动态代理

ProxyLog

public class ProxyLog implements MethodInterceptor {


    public Object getInstance(Class<?> clazz) throws Exception {
        Enhancer enhancer = new Enhancer();
        //要把哪个设置为即将生成的新类父类
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }

    public void log(String methodName) {
        System.out.println("invoke:" + methodName);
    }

    /*
     * 所有生成的代理方法都会调用这个方法来代替原来的方法。
     * 原方法可以通过使用方法对象的正常反射来调用。
     * 或者通过使用方法代理(更快)。
     * @param obj "this",增强的对象。
     * @param method 被拦截方法
     * @param args 参数数组;基元类型被封装。
     * @param proxy 用于调用super(非拦截方法);可根据需要多次调用
     * @throws Throwable 任何异常都可能被抛出;如果是这样,父类方法将不会被调用。
     * @return 任何与代理方法的签名相符的值。返回void的方法将忽略这个值。
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        log(method.getName());
        Object result = methodProxy.invokeSuper(o, objects);
        return result;
    }
}
public class RealRequest implements CustomRequest {
    @Override
    public void setHeader() {
        System.out.println("setHeader");
    }
    @Override
    public void request() {
        System.out.println("hello");
    }
}
生成代理对象
通过java代码

不推荐,新版的cglib只能生成部分动态生成的class

    public static void proxyGenerator() throws Exception {
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "project1\\pattern\\pattern-proxy\\");
        CustomRequest obj = (CustomRequest) new ProxyLog().getInstance(RealRequest.class);
    }
通过jvm工具

通过

java -classpath "D:\java\Jdk8\jdk1.8.0_202\lib\sa-jdi.jar" sun.jvm.hotspot.HSDB

命令
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

生成的代理对象

通过调试可知RealRequest$$EnhancerByCGLIB$$65172dd6是生成返回的代理对象

public class RealRequest$$EnhancerByCGLIB$$65172dd6 extends RealRequest implements Factory {
    private boolean CGLIB$BOUND;
    public static Object CGLIB$FACTORY_DATA;
    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    private static final Callback[] CGLIB$STATIC_CALLBACKS;
    private MethodInterceptor CGLIB$CALLBACK_0;
    private static Object CGLIB$CALLBACK_FILTER;
    private static final Method CGLIB$setHeader$0$Method;
    private static final MethodProxy CGLIB$setHeader$0$Proxy;
    private static final Object[] CGLIB$emptyArgs;
    private static final Method CGLIB$request$1$Method;
    private static final MethodProxy CGLIB$request$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 var0 = Class.forName("com.example.proxy.CglibProxy.RealRequest$$EnhancerByCGLIB$$65172dd6");
        Class var1;
        Method[] var10000 = ReflectUtils.findMethods(new String[]{"setHeader", "()V", "request", "()V"}, (var1 = Class.forName("com.example.proxy.CglibProxy.RealRequest")).getDeclaredMethods());
        CGLIB$setHeader$0$Method = var10000[0];
        CGLIB$setHeader$0$Proxy = MethodProxy.create(var1, var0, "()V", "setHeader", "CGLIB$setHeader$0");
        CGLIB$request$1$Method = var10000[1];
        CGLIB$request$1$Proxy = MethodProxy.create(var1, var0, "()V", "request", "CGLIB$request$1");
        var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
        CGLIB$equals$2$Method = var10000[0];
        CGLIB$equals$2$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$2");
        CGLIB$toString$3$Method = var10000[1];
        CGLIB$toString$3$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$3");
        CGLIB$hashCode$4$Method = var10000[2];
        CGLIB$hashCode$4$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$4");
        CGLIB$clone$5$Method = var10000[3];
        CGLIB$clone$5$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5");
    }

    final void CGLIB$setHeader$0() {
        super.setHeader();
    }

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

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

    final void CGLIB$request$1() {
        super.request();
    }

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

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

    final boolean CGLIB$equals$2(Object var1) {
        return super.equals(var1);
    }

    public final boolean equals(Object var1) {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            Object var2 = var10000.intercept(this, CGLIB$equals$2$Method, new Object[]{var1}, CGLIB$equals$2$Proxy);
            return var2 == null ? false : (Boolean)var2;
        } else {
            return super.equals(var1);
        }
    }

    final String CGLIB$toString$3() {
        return super.toString();
    }

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

        return var10000 != null ? (String)var10000.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 var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            Object var1 = var10000.intercept(this, CGLIB$hashCode$4$Method, CGLIB$emptyArgs, CGLIB$hashCode$4$Proxy);
            return var1 == null ? 0 : ((Number)var1).intValue();
        } else {
            return super.hashCode();
        }
    }

    final Object CGLIB$clone$5() throws CloneNotSupportedException {
        return super.clone();
    }

    protected final Object clone() throws CloneNotSupportedException {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? var10000.intercept(this, CGLIB$clone$5$Method, CGLIB$emptyArgs, CGLIB$clone$5$Proxy) : super.clone();
    }

    public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
        String var10000 = var0.toString();
        switch(var10000.hashCode()) {
        case -508378822:
            if (var10000.equals("clone()Ljava/lang/Object;")) {
                return CGLIB$clone$5$Proxy;
            }
            break;
        case 37055110:
            if (var10000.equals("request()V")) {
                return CGLIB$request$1$Proxy;
            }
            break;
        case 1326039942:
            if (var10000.equals("setHeader()V")) {
                return CGLIB$setHeader$0$Proxy;
            }
            break;
        case 1826985398:
            if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                return CGLIB$equals$2$Proxy;
            }
            break;
        case 1913648695:
            if (var10000.equals("toString()Ljava/lang/String;")) {
                return CGLIB$toString$3$Proxy;
            }
            break;
        case 1984935277:
            if (var10000.equals("hashCode()I")) {
                return CGLIB$hashCode$4$Proxy;
            }
        }

        return null;
    }

    public RealRequest$$EnhancerByCGLIB$$65172dd6() {
        CGLIB$BIND_CALLBACKS(this);
    }

    public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
        CGLIB$THREAD_CALLBACKS.set(var0);
    }

    public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
        CGLIB$STATIC_CALLBACKS = var0;
    }

    private static final void CGLIB$BIND_CALLBACKS(Object var0) {
        RealRequest$$EnhancerByCGLIB$$65172dd6 var1 = (RealRequest$$EnhancerByCGLIB$$65172dd6)var0;
        if (!var1.CGLIB$BOUND) {
            var1.CGLIB$BOUND = true;
            Object var10000 = CGLIB$THREAD_CALLBACKS.get();
            if (var10000 == null) {
                var10000 = CGLIB$STATIC_CALLBACKS;
                if (var10000 == null) {
                    return;
                }
            }

            var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
        }

    }

    public Object newInstance(Callback[] var1) {
        CGLIB$SET_THREAD_CALLBACKS(var1);
        RealRequest$$EnhancerByCGLIB$$65172dd6 var10000 = new RealRequest$$EnhancerByCGLIB$$65172dd6();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }

    public Object newInstance(Callback var1) {
        CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
        RealRequest$$EnhancerByCGLIB$$65172dd6 var10000 = new RealRequest$$EnhancerByCGLIB$$65172dd6();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }

    public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
        CGLIB$SET_THREAD_CALLBACKS(var3);
        RealRequest$$EnhancerByCGLIB$$65172dd6 var10000 = new RealRequest$$EnhancerByCGLIB$$65172dd6;
        switch(var1.length) {
        case 0:
            var10000.<init>();
            CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
            return var10000;
        default:
            throw new IllegalArgumentException("Constructor not found");
        }
    }

    public Callback getCallback(int var1) {
        CGLIB$BIND_CALLBACKS(this);
        MethodInterceptor var10000;
        switch(var1) {
        case 0:
            var10000 = this.CGLIB$CALLBACK_0;
            break;
        default:
            var10000 = null;
        }

        return var10000;
    }

    public void setCallback(int var1, Callback var2) {
        switch(var1) {
        case 0:
            this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
        default:
        }
    }

    public Callback[] getCallbacks() {
        CGLIB$BIND_CALLBACKS(this);
        return new Callback[]{this.CGLIB$CALLBACK_0};
    }

    public void setCallbacks(Callback[] var1) {
        this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
    }

    static {
        CGLIB$STATICHOOK1();
    }
}
分析

可以看到重写了RealRequest类所有的方法,包括从Object继承的方法,
并且获得了所有Method并有与之对应的MethodProxy
例如com.example.proxy.JdkProxy.custom.CustomRequest#setHeader

...
    private static final Method CGLIB$setHeader$0$Method;
    private static final MethodProxy CGLIB$setHeader$0$Proxy;
...

这些方法在重写的setHeader中都有调用

//代理方法(methodProxy.invokeSuper 会调用)
final void CGLIB$setHeader$0() {super.setHeader();}
//被代理方法(methodProxy.invoke 会调用,这就是为什么在拦截器中调用 methodProxy.invoke 会死循环,一直在调 用拦截器)
    public final void setHeader() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
        //public Object getInstance(Class<?> clazz) throws Exception {
        //Enhancer enhancer = new Enhancer();
        //要把哪个设置为即将生成的新类父类
        //enhancer.setSuperclass(clazz);
        //enhancer.setCallback(this);
        //return enhancer.create();
    	//}
        //var10000就是通过enhancer.setCallback(this)传入的
        //方法拦截器(ProxyLog implements MethodInterceptor)
        //调用com.example.proxy.CglibProxy.ProxyLog#intercept
        //(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable
            var10000.intercept(this, CGLIB$setHeader$0$Method, CGLIB$emptyArgs, CGLIB$setHeader$0$Proxy);
        } else {
            super.setHeader();
        }
    }

具体invoke和invokeSuper分别调用哪个可以从MethodProxy的一个注释上了解

	//org.springframework.cglib.proxy.MethodProxy#getSuperName
	/**
	 * Return the name of the synthetic method created by CGLIB which is
	 * used by {@link #invokeSuper} to invoke the superclass
	 * (non-intercepted) method implementation. The parameter types are
	 * the same as the proxied method.
	 */
	 /**
	返回由CGLIB创建的合成方法的名称,
	该方法被{@link #invokeSuper}用来调用父类。
	(非拦截)方法的实现。参数类型与代理方法相同。
	 */
	public String getSuperName() {
		return sig2.getName();
	}

调用流程

this[RealRequest$$EnhancerByCGLIB$$65172dd6] ProxyLog MethodProxy setHeader() this.MethodInterceptor intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) log(String methodName) invokeSuper(Object obj, Object[] args) CGLIB$setHeader$0 super.setHeader() this[RealRequest$$EnhancerByCGLIB$$65172dd6] ProxyLog MethodProxy



主要分析org.springframework.cglib.proxy.MethodProxy#invokeSuper

public class MethodProxy {
//方法签名,保留了方法的名称,返回类型和参数类型
    private Signature sig1;
    private Signature sig2;
	private void init()
    	{
    	...
                    fci.f1 = helper(ci, ci.c1);
                    fci.f2 = helper(ci, ci.c2);
                    //根据方法签名获取方法索引值
                    fci.i1 = fci.f1.getIndex(sig1);
                    fci.i2 = fci.f2.getIndex(sig2);
                    fastClassInfo = fci;
    	...
    	}
    	private static class FastClassInfo {
    		FastClass f1;
   		 	FastClass f2;
   		 	int i1;
        	int i2;
    		private FastClassInfo() {
    		}
		}
	org.springframework.cglib.proxy.MethodProxy#invokeSuper
    public Object invokeSuper(Object obj, Object[] args) throws Throwable {
        try {
            this.init();
            MethodProxy.FastClassInfo fci = this.fastClassInfo;
            //fci.f2
            //FastClassInfo.FastClass 
            return fci.f2.invoke(fci.i2, obj, args);
        } catch (InvocationTargetException var4) {
            throw var4.getTargetException();
        }
    }
    
    ...

上面代码调用过程就是获取到代理类对应的 FastClass,根据方法签名获取了方法索引,并执行了被代理方法。

具体执行过程,还记得之前生成三个class文件吗?
在这里插入图片描述
RealRequest$$EnhancerByCGLIB$$65172dd6$$FastClassByCGLIB$$2f48364e
就是RealRequest$$EnhancerByCGLIB$$65172dd6
的FastClass
下面我们看看源码

/**
 * A representation of a method signature, containing the method name,
 * return type, and parameter types.
 */
public class Signature {
    private String name;
    private String desc;
public Signature(String name, Type returnType, Type[] argumentTypes) {
        this(name, Type.getMethodDescriptor(returnType, argumentTypes));
}
public String toString() {return name + desc;}
}
	net.sf.cglib.proxy.MethodProxy#init
	//FastClass 并不是跟代理类一块生成的,而是在第一次执行 MethodProxy
//invoke/invokeSuper 时生成的并放在了缓存中。
//MethodProxy invoke/invokeSuper 都调用了 init()
    private void init()
    {
        /* 
         * Using a volatile invariant allows us to initialize the FastClass and
         * method index pairs atomically.
         * 
         * Double-checked locking is safe with volatile in Java 5.
         * volatile 修饰的变量生成通过双重检查锁在Java5是安全的
         * Before 1.5 this code could allow fastClassInfo to be 
         * instantiated more than once, which appears to be benign.
         * 但在1.5之前fastClassInfo可以被实例化多次,但似乎并不影响
         * 
         */
        if (fastClassInfo == null)
        {
            synchronized (initLock)
            {
                if (fastClassInfo == null)
                {
                    CreateInfo ci = createInfo;
                    FastClassInfo fci = new FastClassInfo();
                    //如果缓存中就取出,没有就生成新的 FastClass
                    fci.f1 = helper(ci, ci.c1);
                    fci.f2 = helper(ci, ci.c2);
                    fci.i1 = fci.f1.getIndex(sig1);//获取方法的 index
                    fci.i2 = fci.f2.getIndex(sig2);
                    fastClassInfo = fci;
                    createInfo = null;
                }
            }
        }
    }
    net.sf.cglib.proxy.MethodProxy#invokeSuper
    public Object invokeSuper(Object obj, Object[] args) throws Throwable 		
    {
   			...
            return fci.f2.invoke(fci.i2, obj, args);
			...
    }
	/**
     * Invoke the method with the specified index.
     * 调用指定索引的方法
     * @see getIndex(name, Class[])
     * @param index the method index(方法索引)
     * @param obj the object the underlying method is invoked from(调用基础方法的对象)
     * @param args the arguments used for the method call(用于方法调用的参数)
     * @throws java.lang.reflect.InvocationTargetException if the underlying method throws an exception
     */
    net.sf.cglib.reflect.FastClass#invoke(int, java.lang.Object, java.lang.Object[])
    abstract public Object invoke(int index, Object obj, Object[] args) throws InvocationTargetException;
    //根据方法签名获取方法索引
    public int getIndex(Signature var1) {
        String var10000 = var1.toString();
        switch(var10000.hashCode()) {
        case -2092735716:
            if (var10000.equals("CGLIB$setHeader$1()V")) {
                return 20;
            }
            break;
        case -1870561232:
            if (var10000.equals("CGLIB$findMethodProxy(Lorg/springframework/cglib/core/Signature;)Lorg/springframework/cglib/proxy/MethodProxy;")) {
                return 21;
            }
            break;
        case -1745842178:
            if (var10000.equals("setCallbacks([Lorg/springframework/cglib/proxy/Callback;)V")) {
                return 10;
            }
            break;
        case -1641413109:
            if (var10000.equals("newInstance([Lorg/springframework/cglib/proxy/Callback;)Ljava/lang/Object;")) {
                return 4;
            }
            break;
        case -1457535688:
            if (var10000.equals("CGLIB$STATICHOOK1()V")) {
                return 22;
            }
            break;
        case -1411812934:
            if (var10000.equals("CGLIB$hashCode$4()I")) {
                return 17;
            }
            break;
        case -1034266769:
            if (var10000.equals("CGLIB$SET_STATIC_CALLBACKS([Lorg/springframework/cglib/proxy/Callback;)V")) {
                return 14;
            }
            break;
        case -1025895669:
            if (var10000.equals("CGLIB$SET_THREAD_CALLBACKS([Lorg/springframework/cglib/proxy/Callback;)V")) {
                return 13;
            }
            break;
        case -988317324:
            if (var10000.equals("newInstance([Ljava/lang/Class;[Ljava/lang/Object;[Lorg/springframework/cglib/proxy/Callback;)Ljava/lang/Object;")) {
                return 5;
            }
            break;
        case -508378822:
            if (var10000.equals("clone()Ljava/lang/Object;")) {
                return 3;
            }
            break;
        case 37055110:
            if (var10000.equals("request()V")) {
                return 7;
            }
            break;
        case 374345669:
            if (var10000.equals("CGLIB$equals$2(Ljava/lang/Object;)Z")) {
                return 16;
            }
            break;
        case 610042816:
            if (var10000.equals("newInstance(Lorg/springframework/cglib/proxy/Callback;)Ljava/lang/Object;")) {
                return 6;
            }
            break;
        case 1132856532:
            if (var10000.equals("getCallbacks()[Lorg/springframework/cglib/proxy/Callback;")) {
                return 12;
            }
            break;
        case 1246779367:
            if (var10000.equals("setCallback(ILorg/springframework/cglib/proxy/Callback;)V")) {
                return 9;
            }
            break;
        case 1326039942:
            if (var10000.equals("setHeader()V")) {
                return 8;
            }
            break;
        case 1364367423:
            if (var10000.equals("getCallback(I)Lorg/springframework/cglib/proxy/Callback;")) {
                return 11;
            }
            break;
        case 1517819849:
            if (var10000.equals("CGLIB$toString$3()Ljava/lang/String;")) {
                return 18;
            }
            break;
        case 1826985398:
            if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                return 0;
            }
            break;
        case 1913648695:
            if (var10000.equals("toString()Ljava/lang/String;")) {
                return 1;
            }
            break;
        case 1984935277:
            if (var10000.equals("hashCode()I")) {
                return 2;
            }
            break;
        case 2011844968:
            if (var10000.equals("CGLIB$clone$5()Ljava/lang/Object;")) {
                return 19;
            }
            break;
        case 2014567037:
            if (var10000.equals("CGLIB$request$0()V")) {
                return 15;
            }
        }

        return -1;
    }

调用了 Signature 的toString,而toString的返回值由方法名加返回类型与参数类型的MethodDescriptor(方法描述符)构成
接着通过toString的返回值的hashCode值选择方法对应的int值
再根据索引值(int值)调用net.sf.cglib.reflect.FastClass#invoke(int, java.lang.Object, java.lang.Object[]),调用目标方法

手写实现JDK的动态代理

既然 JDK Proxy 功能如此强大,那么它是如何实现的呢? 我们现在来探究一下原理,并模仿JDK Proxy自己动手写一个属于自己的动态代理。 我们都知道 JDK Proxy 采用字节重组,重新生的对象来替代原始的对象以达到动态代理 的目的。JDK Proxy 生成对象的步骤如下:

1.拿到被代理对象的引用,通过反射获取它所有的接口.

2.JDK Proxy类根据传入的类加载器,接口,和调用处理类,重新生成一个新的类,同时新的类实现被代理类的所有接口.

3.动态生成java代码,把原有的方法调用转换为经过调用处理类调用

4.编译新生成的 Java 代码.class

5.再重新加载到 JVM 中运行。

以上这个过程就叫字节码重组。JDK 中有一个规范,在 ClassPath 下只要是$开头的 class 文件一般都是自动生成的。

生成Proxy类代码

可以通过如下代码生成代理类的代码了解详情

    public static void proxyGenerator() throws Exception {
        byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{CustomRequest.class});
        //会在项目下生成一个$Proxy0.class
        FileOutputStream os = new FileOutputStream("$Proxy0.class");
        os.write(bytes);
        os.close();
    }

生成的代理类

import com.example.proxy.JdkProxy.CustomRequest;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements CustomRequest {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m4;
    private static Method m0;
	//var1就是java.lang.reflect.Proxy#newProxyInstance
	//(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
	//中的InvocationHandler 
    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void setHeader() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void request() throws  {
        try {
            super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.example.proxy.JdkProxy.CustomRequest").getMethod("setHeader");
            m4 = Class.forName("com.example.proxy.JdkProxy.CustomRequest").getMethod("request");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}
小结

可以看到在静态块中获得了被代理类的所有方法和object的公共方法,在构造函数初始化的时候定义了InvocationHandler h,实现了接口方法,方法处理通过传入的h在实现和重写的方法中调用自身的invoke(Object proxy, Method method, Object[] args)方法处理被代理类的所有方法;

主要就是通过字节码重组生成了新的代码,代理了被代理类的所有方法.

手写实现

根据上述原理尝试手写一个
Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this)的逻辑

Proxy和CustomClassLoad代码来源于网络,有空了再自己手写一个.
CustomClassLoad

public class CustomClassLoad extends ClassLoader {
    private File classPathFile;
    public CustomClassLoad(){
        String classPath = CustomClassLoad.class.getResource("").getPath();
        this.classPathFile = new File(classPath);
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {

        String className = CustomClassLoad.class.getPackage().getName() + "." + name;
        if(classPathFile  != null){
            File classFile = new File(classPathFile,name.replaceAll("\\.","/") + ".class");
            if(classFile.exists()){
                FileInputStream in = null;
                ByteArrayOutputStream out = null;
                try{
                    in = new FileInputStream(classFile);
                    out = new ByteArrayOutputStream();
                    byte [] buff = new byte[1024];
                    int len;
                    while ((len = in.read(buff)) != -1){
                        out.write(buff,0,len);
                    }
                    return defineClass(className,out.toByteArray(),0,out.size());
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
        return null;
    }
}

CustomInvocationHandler

public interface CustomInvocationHandler {
    public Object invoke(Object invoker, Method method, Object[] args) throws Throwable;
}

CustomProxy

public class CustomProxy {
    public static final String ln="\r\n";
    public static Object newProxyInstance(CustomClassLoad classLoader, Class<?> [] interfaces, CustomInvocationHandler h){
        try {
            //1、动态生成源代码.java文件
            String src = generateSrc(interfaces);

//           System.out.println(src);
            //2、Java文件输出磁盘
            String filePath = CustomProxy.class.getResource("").getPath();
//           System.out.println(filePath);
            File f = new File(filePath + "$Proxy0.java");
            FileWriter fw = new FileWriter(f);
            fw.write(src);
            fw.flush();
            fw.close();

            //3、把生成的.java文件编译成.class文件
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager manage = compiler.getStandardFileManager(null,null,null);
            Iterable iterable = manage.getJavaFileObjects(f);

            JavaCompiler.CompilationTask task = compiler.getTask(null,manage,null,null,null,iterable);
            task.call();
            manage.close();

            //4、编译生成的.class文件加载到JVM中来
            Class proxyClass =  classLoader.findClass("$Proxy0");
            Constructor c = proxyClass.getConstructor(CustomInvocationHandler.class);
            f.delete();

            //5、返回字节码重组以后的新的代理对象
            return c.newInstance(h);
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    private static String generateSrc(Class<?>[] interfaces){
        StringBuffer sb = new StringBuffer();
        sb.append("package com.example.proxy.JdkProxy.custom;" + ln);
        sb.append("import com.example.proxy.JdkProxy.custom.CustomRequest;" + ln);
        sb.append("import java.lang.reflect.*;" + ln);
        sb.append("public class $Proxy0 implements " + interfaces[0].getName() + "{" + ln);
        sb.append("CustomInvocationHandler h;" + ln);
        sb.append("public $Proxy0(CustomInvocationHandler h) { " + ln);
        sb.append("this.h = h;");
        sb.append("}" + ln);
        for (Method m : interfaces[0].getMethods()){
            Class<?>[] params = m.getParameterTypes();

            StringBuffer paramNames = new StringBuffer();
            StringBuffer paramValues = new StringBuffer();
            StringBuffer paramClasses = new StringBuffer();

            for (int i = 0; i < params.length; i++) {
                Class clazz = params[i];
                String type = clazz.getName();
                String paramName = toLowerFirstCase(clazz.getSimpleName());
                paramNames.append(type + " " +  paramName);
                paramValues.append(paramName);
                paramClasses.append(clazz.getName() + ".class");
                if(i > 0 && i < params.length-1){
                    paramNames.append(",");
                    paramClasses.append(",");
                    paramValues.append(",");
                }
            }

            sb.append("public " + m.getReturnType().getName() + " " + m.getName() + "(" + paramNames.toString() + ") {" + ln);
            sb.append("try{" + ln);
            sb.append("Method m = " + interfaces[0].getName() + ".class.getMethod(\"" + m.getName() + "\",new Class[]{" + paramClasses.toString() + "});" + ln);
            sb.append((hasReturnValue(m.getReturnType()) ? "return " : "") + getCaseCode("this.h.invoke(this,m,new Object[]{" + paramValues + "})",m.getReturnType()) + ";" + ln);
            sb.append("}catch(Error _ex) { }");
            sb.append("catch(Throwable e){" + ln);
            sb.append("throw new UndeclaredThrowableException(e);" + ln);
            sb.append("}");
            sb.append(getReturnEmptyCode(m.getReturnType()));
            sb.append("}");
        }
        sb.append("}" + ln);
        return sb.toString();
    }


    private static Map<Class,Class> mappings = new HashMap<Class, Class>();
    static {
        mappings.put(int.class,Integer.class);
    }

    private static String getReturnEmptyCode(Class<?> returnClass){
        if(mappings.containsKey(returnClass)){
            return "return 0;";
        }else if(returnClass == void.class){
            return "";
        }else {
            return "return null;";
        }
    }

    private static String getCaseCode(String code,Class<?> returnClass){
        if(mappings.containsKey(returnClass)){
            return "((" + mappings.get(returnClass).getName() +  ")" + code + ")." + returnClass.getSimpleName() + "Value()";
        }
        return code;
    }

    private static boolean hasReturnValue(Class<?> clazz){
        return clazz != void.class;
    }

    private static String toLowerFirstCase(String src){
        char [] chars = src.toCharArray();
        chars[0] += 32;
        return String.valueOf(chars);
    }

}

CustomRequest

//JDK动态代理转换类,根据接口转换
public interface CustomRequest {

    public void request();

    public void setHeader();
}

ProxyLog

public class ProxyLog implements CustomInvocationHandler {
    private Object target;
    public Object getInstance(Object target) throws Exception {
        this.target = target;
        Class<?> clazz = target.getClass();
        //根据clazz.getInterfaces()获得的接口,得到可以转换的类型和调用方法,无法直接转换为clazz
        return CustomProxy.newProxyInstance(new CustomClassLoad(), clazz.getInterfaces(), this);
    }
    /*   proxy为根据ProxyLog实现的invoke方法生成的代理对象
       也就是通过Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this)
       返回的对象
       ((ProxyLog) ((Proxy) proxy).h).target==target
       method是当前代理对象调用的方法,args是当前调用方法
       传递的参数,result为方法调用的返回值Void方法返回null*/
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log(method.getName());
        Object result = method.invoke(target, args);
        return result;
    }
    public void log(String methodName) {
        System.out.println("invoke:" + methodName);
    }
}

CustomRequest

public class RealRequest implements CustomRequest {
    @Override
    public void setHeader() {
        System.out.println("setHeader");
    }
    @Override
    public void request() {
        System.out.println("hello");
    }
}

Test

public class Test {
    public static void main(String[] args) throws Exception {
        test();
    }
    public static void test() throws Exception {
        CustomRequest request = ((CustomRequest) new ProxyLog().getInstance(new RealRequest()));
        request.request();
        request.setHeader();
        request.toString();
    }
}

结果

invoke:request
hello
invoke:setHeader
setHeader
小结

主要就是字节码的拼接,然后交由JDK编译加载到虚拟机

总结CGLib和JDK Proxy的根本区别

1.JDK 动态代理是实现了被代理对象的接口,CGLib 是继承了被代理对象。
2.JDK 和 CGLib 都是在运行期生成字节码,JDK 是直接写 Class 字节码,CGLib使用 ASM 框架写 Class 字节码,Cglib代理实现更复杂,生成代理类的效率比JDK的直接生成低。
3.JDK 调用代理方法,是通过反射机制调用,CGLib 是通过 FastClass 机制直接调用方法, CGLib 执行效率更高。
CGLib动态代理执行代理方法效率之所以比JDK的高是
因为Cglib采用了 FastClass 机制,它的原理简单来说就是:
为代理类和被代理类各生成一个Class,这个Class 会为代理类
或被代理类的方法分配一个index(int 类型)。这个index当做一个入参,
FastClass 就可以直接定位要调用的方法直接进行调用,这样省去了反射调用,
所以调用效率比 JDK 动态代理通过反射调用高

参考

Cglib动态代理反编译生成类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值