转载

JDK动态代理实现原理浅析

代理模式理解起来还是比较简单的。大致可以理解为代理人与被代理人实现同一接口定义的行为,在外部调用者调用定义的行为时,不直接调用代理人的提供的行为,而是调用代理人提供的行为,此时调用者是不会感觉到区别的,因为代理人有着和被代理人的行为定义是相同的,调用者感觉不到区别(也就是实现了同一接口),在代理人的行为中在去调用被代理人的行为,并且可以实现增强。记得前几年有部电影,我觉得其实就很好的诠释了”代理”这个概念,想必看了就明白代理模式是怎么回事了。

JDK动态代理实现原理浅析 JDK动态代理实现原理浅析

更多的不再细说了,这不是本文的重点。我们这次主要是学习动态代理。

关于动态代理

上边说的代理模式实际上细分的话,可以分为静态代理和动态代理,在实际编码中,代理模式一般是以动态代理的形式出现的。

JDK动态代理

动态代理的实现途径有很多种,比如用JDK动态代理和CGLIB动态代理,本篇文章我们主要关注JDK动态代理。

用法

首先了解一下怎样使用。来看一个具体的例子吧:

package com.github.since1986.learn.java.proxy;

//定义好行为
public interface InterfaceA {

    String doSomething(String param);
}
//定义好默认实现
package com.github.since1986.learn.java.proxy;

public class ImplementationA implements InterfaceA {

    @Override
    public String doSomething(String param) {
        return String.format("hello, %s.", param);
    }
}
package com.github.since1986.learn.java.proxy.dynamic;

import com.github.since1986.learn.java.proxy.ImplementationA;
import com.github.since1986.learn.java.proxy.InterfaceA;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class DynamicProxyCase {

    public static void main(String[] args) {

        //生成代理
        InterfaceA proxyA = (InterfaceA) Proxy.newProxyInstance(DynamicProxyCase.class.getClassLoader(), new Class[]{InterfaceA.class}, new InvocationHandler() {

            //反射调用默认行为(并可在此实现增强)
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
                return method.invoke(new ImplementationA(), args) + " Bye~";
            }
        });

        //调用接口定义的行为
        System.out.println(proxyA.doSomething("Test"));
    }
}

运行结果:

hello, Test Bye~.

总结起来,写JDK动态代理一共4步(比把大象装到冰箱里多一步):

  1. 定义行为(也就是接口)
  2. 实现一个默认行为(也就是给第1步中定义的接口提供一个默认实现)
  3. 实现一个回调方法(在这个回调中调用第2步中的默认行为)

    java.lang.reflect.InvocationHandler#invoke(Object proxy, Method method, Object[] args) throws Throwable;
    
  4. 调用 Proxy#newProxyInstance 生成代理实例

    java.lang.reflect.Proxy#newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
    

原理

了解了怎样使用,我们再来看看JDK动态代理是怎么实现的吧。

先看

java.lang.reflect.Proxy#newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

这个方法,这个方法是整个动态代理流程的入口点。

在这个方法中会去反射获得我们定义的接口的 Class

/*
 * Look up or generate the designated proxy class.
 */
Class<?> cl = getProxyClass0(loader, intfs); //intfs是克隆的参数传进来的interfaces:Class<?>[] intfs = interfaces.clone();

然后通过这个Class拿到 java.lang.reflect.Constructor

final Constructor<?> cons = cl.getConstructor(constructorParams);

再通过 java.lang.reflect.Constructorjava.lang.reflect.Constructor#newInstance 来创建代理的实例并返回,所以我们调用 java.lang.reflect.Proxy#newProxyInstance 返回的代理实例其实是 java.lang.reflect.Constructor#newInstance 提供的。

接下来再来看 java.lang.reflect.Constructor#newInstance

ConstructorAccessor ca = constructorAccessor;   // read volatile
if (ca == null) {
    ca = acquireConstructorAccessor();
}
@SuppressWarnings("unchecked")
T inst = (T) ca.newInstance(initargs);
return inst;

注意这一段, java.lang.reflect.Constructor#newInstance 返回的实际上是 sun.reflect.ConstructorAccessor#newInstance 所返回的

我们再转到 sun.reflect.ConstructorAccessor#newInstance ,可以看到这个方法是个接口方法

JDK动态代理实现原理浅析

我们打开它其中一个实现 sun.reflect.NativeConstructorAccessorImpl ,可以看到再往下就是开始操作 class 文件结构了,我们到此基本上大致了解一部分JDK动态代理的原理了,那就是生成 class 文件。那么我们如何看到生成的 class 文件呢?另外前边提到的 InvocationHandler 在流程中没有出现啊?不用着急,我们一一来。

怎样看到生成的 class 文件呢?在生成动态代理前设置一个 Properties 就可以了(这个 Properties 源码位置在 sun.misc.ProxyGenerator#saveGeneratedFiles ): System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); 。设置好后,我们可以看到生成的以 $ 开头的 class 文件:

JDK动态代理实现原理浅析

用idea打开这个 class 文件看反编译后的代码:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.sun.proxy;

import com.github.since1986.learn.java.proxy.InterfaceA;
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 InterfaceA { //动态生成的代理类,实现了我们定义的接口
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    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 String doSomething(String var1) throws  { //我们定义的行为(接口方法)
        try {
            return (String)super.h.invoke(this, m3, new Object[]{var1}); //注意这里
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    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.github.since1986.learn.java.proxy.InterfaceA").getMethod("doSomething", Class.forName("java.lang.String"));
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

注意上边代码 doSomething 方法中这一段:

return (String)super.h.invoke(this, m3, new Object[]{var1});

这里面的 super.hjava.lang.reflect.Proxy#h 这个属性:

/**
 * the invocation handler for this proxy instance.
 * @serial
 */
protected InvocationHandler h;

也就是说 InvocationHandler 是被插入到了生成的 class 文件中的。

我么继续看 h.invoke(this, m3, new Object[]{var1}); ,在这个调用中传入的参数,第一个 this 就是当前生成的 $Proxy0 的实例,第二个参数 m3 实际上就是我们定义的接口方法

m3 = Class.forName("com.github.since1986.learn.java.proxy.InterfaceA").getMethod("doSomething", Class.forName("java.lang.String"));

第三个参数是被传入的被调用的接口方法的实际参数。这个 h.invoke 就是前面我们提到的那个 java.lang.reflect.InvocationHandler 的方法:

/**
 * Processes a method invocation on a proxy instance and returns
 * the result.  This method will be invoked on an invocation handler
 * when a method is invoked on a proxy instance that it is
 * associated with.
 *
 * @param   proxy the proxy instance that the method was invoked on
 *
 * @param   method the {@code Method} instance corresponding to
 * the interface method invoked on the proxy instance.  The declaring
 * class of the {@code Method} object will be the interface that
 * the method was declared in, which may be a superinterface of the
 * proxy interface that the proxy class inherits the method through.
 *
 * @param   args an array of objects containing the values of the
 * arguments passed in the method invocation on the proxy instance,
 * or {@code null} if interface method takes no arguments.
 * Arguments of primitive types are wrapped in instances of the
 * appropriate primitive wrapper class, such as
 * {@code java.lang.Integer} or {@code java.lang.Boolean}.
 *
 * @return  the value to return from the method invocation on the
 * proxy instance.  If the declared return type of the interface
 * method is a primitive type, then the value returned by
 * this method must be an instance of the corresponding primitive
 * wrapper class; otherwise, it must be a type assignable to the
 * declared return type.  If the value returned by this method is
 * {@code null} and the interface method's return type is
 * primitive, then a {@code NullPointerException} will be
 * thrown by the method invocation on the proxy instance.  If the
 * value returned by this method is otherwise not compatible with
 * the interface method's declared return type as described above,
 * a {@code ClassCastException} will be thrown by the method
 * invocation on the proxy instance.
 *
 * @throws  Throwable the exception to throw from the method
 * invocation on the proxy instance.  The exception's type must be
 * assignable either to any of the exception types declared in the
 * {@code throws} clause of the interface method or to the
 * unchecked exception types {@code java.lang.RuntimeException}
 * or {@code java.lang.Error}.  If a checked exception is
 * thrown by this method that is not assignable to any of the
 * exception types declared in the {@code throws} clause of
 * the interface method, then an
 * {@link UndeclaredThrowableException} containing the
 * exception that was thrown by this method will be thrown by the
 * method invocation on the proxy instance.
 *
 * @see     UndeclaredThrowableException
 */
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;

就是在这个方法中,我们调用了实际的默认实现,并实现了对默认实现的增强:

//反射调用默认行为(并可在此实现增强)
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
    return method.invoke(new ImplementationA(), args) + " Bye~";
}

可以看到实际上这个方法中的3个参数 Object proxy, Method method, Object[] args 就是 $Proxy0 通过 h.invoke(this, m3, new Object[]{var1}); 传递给我们的,也就是说,我们实现的 InvocationHandlerpublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable; 实际上是一个 回调 ,也就是我们预先定义好的,然后JDK生成的类 $Proxy0 回过来调用的。

到这里,整个流程基本上就清楚了,总结一下:JDK动态代理的基本原理就是 我们定义好接口和默认实现,JDK根据通过生成 class 文件的方式”动态”的生成一个代理类,这个代理类实现了我们定义的接口,并在接口实现方法中回调了我们通过 InvocationHandler 定义的处理流程,这个处理流程中我们回去调用默认实现,并提供增强。

原文  https://since1986.github.io/blog/bf178159.html
正文到此结束
Loading...