29.AOP源码之JDK动态代理

275 阅读8分钟

5.JdkDynamicAopProxy#getProxy

image.png

大家可以看到,首先我们根据java规范来编写代码,也就是源码xxx.java文件,接着会使用javac命令将源码文件xxx.java编译生成字节码文件xxx.class,接着有类加载器将字节码xxx.class加载到Java虚拟机中,也就是我们常说的JVM,当字节码xxx.class被加载到JVM中后,这个类就可以被正常调用了,大概就是这个流程。

那现在大家思考一下,我们即将要分析的jdk动态代理是不是也是这样运行的呢?

答案当然是肯定的,jdk动态代理不就是一个代理类嘛,这个代理类也是java代码,只不过我们没有手动编写代理类的xxx.java文件,而是直接生成了代理类的字节码,也就是xxx.class文件,但是要想运行代理类的代码,同样也需要将代理类的字节码通过类加载器给加载到JVM中的。

说白了就是在运行代理类代码之前,一定会先生成代理类的字节码,接着将代理类的字节码通过类加载器加载到JVM,然后才可以运行代理类的构造方法创建出来一个代理对象出来,大概是这样子的流程。

JdkDynamicAopProxy 实现了InvocationHandler接口

JdkDynamicAopProxy中的advised是我们的代理工厂ProxyFactory

JdkDynamicAopProxy#getProxy

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
    /*  proxiedInterfaces = {Class[4]@1801}
    0 = {Class@1765} "interface aop.LogService"
    1 = {Class@1794} "interface org.springframework.aop.SpringProxy"
    2 = {Class@1782} "interface org.springframework.aop.framework.Advised"
    3 = {Class@1795} "interface org.springframework.core.DecoratingProxy"
    */
   //拿到要被代理对象的所有接口
    Class<?>[] proxiedInterfaces = 
            AopProxyUtils.completeProxiedInterfaces(this.advised, true);
    findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
    //this是JdkDynamicAopProxy 实现了InvocationHandler接口
    //JdkDynamicAopProxy中的属性advised是我们的代理工厂ProxyFactory
    //ProxyFactory封装了各种参数比如被代理类的实例以及advisors
    //advisor中又封装了方法和方法的切面表达式 
    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

Proxy.newProxyInstance()

Proxy.newProxyInstance()方法有三个比较核心的参数。

分别是类加载器、被代理对象的所有接口列表以及回调程序。

在这里我们可以看到,Spring先调用completeProxiedInterfaces()方法获取到了被代理对象要代理的所有接口,然后将这个接口作为入参传了进去。

另外我们还看到传给Proxy.newProxyInstance()方法的回调程序竟然是this,说白了就是将当前的JdkDynamicAopProxy对象作为回调程序传了进去。

this是JdkDynamicAopProxy 实现了InvocationHandler接口

JdkDynamicAopProxy中的属性advised是我们的代理工厂ProxyFactory

ProxyFactory封装了各种参数比如被代理类的实例以及advisors,advisor中又封装了方法和方法的切面表达式。

参数都设置完毕后,我们就可以通过Proxy.newProxyInstance()方法拿到一个jdk代理对象了。

其实这个newProxyInstance()方法的代码还是比较清晰的,就是先获取代理类的Class对象,然后再获取构造方法,最后通过构造方法创建了代理类的对象。

/***
InvocationHandler是JdkDynamicAopProxy 
JdkDynamicAopProxy 实现了InvocationHandler接口 
JdkDynamicAopProxy中的属性advised是我们的代理工厂ProxyFactory
ProxyFactory封装了各种参数比如被代理类的实例以及advisors,advisor中又封装了增强方法和增强方法的切面表达式。
***/
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,
InvocationHandler h) throws IllegalArgumentException{
    Objects.requireNonNull(h);

    final Class<?>[] intfs = interfaces.clone();
    final SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
    }

    /***
    查找或生成指定的代理类,核心逻辑就在这里
    这里主要做两件事儿
        其一就是生成代理类字节码
        其二将生成的字节码加载到JVM中
    ***/
    Class<?> cl = getProxyClass0(loader, intfs);

    try {
        if (sm != null) {
            checkNewProxyPermission(Reflection.getCallerClass(), cl);
        }
        // 获取代理类的构造方法      
        // private static final Class<?>[] constructorParams 
        //						        = { InvocationHandler.class };
        final Constructor<?> cons = cl.getConstructor(constructorParams);
        final InvocationHandler ih = h;
        if (!Modifier.isPublic(cl.getModifiers())) {
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                public Void run() {
                    cons.setAccessible(true);
                    return null;
                }
            });
        }
       /***
        使用反射通过构造方法创建代理类对象
        h是JdkDynamicAopProxy 实现了InvocationHandler接口
        JdkDynamicAopProxy中的属性advised是我们的代理工厂ProxyFactory
                ProxyFactory封装了各种参数比如被代理类的实例以及advisors
                advisor中又封装了增强方法和增强方法的切面表达式。
        ***/
        return cons.newInstance(new Object[]{h});
    } catch (IllegalAccessException|InstantiationException e) {
        throw new InternalError(e.toString(), e);
    } catch (InvocationTargetException e) {
        Throwable t = e.getCause();
        if (t instanceof RuntimeException) {
            throw (RuntimeException) t;
        } else {
            throw new InternalError(t.toString(), t);
        }
    } catch (NoSuchMethodException e) {
        throw new InternalError(e.toString(), e);
    }
}

5.1动态生成字节码文件

Class<?> cl = getProxyClass0(loader, intfs);

在getProxyClass0()方法中,在这个方法中不但生成了代理类,还将生成的代理类加载到了JVM中,这样我们才可以获取到代理类中的构造方法。此时我们打开getProxyClass0()方法,然后我们会看到下边的代码:

    // 初始化proxyClassCache,注意它的value是ProxyClassFactory类型
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
    proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());    

private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) {
    if (interfaces.length > 65535) {
        throw new IllegalArgumentException("interface limit exceeded");
    }

    // 缓存中存在就从缓存中获取代理类,缓存中不存在就使用ProxyClassFactory创建代理类
    return proxyClassCache.get(loader, interfaces);
}

代码所在类的全限定类名:java.lang.reflect.Proxy#getProxyClass0

5.2使用InvocationHandler构建实例

/***
使用反射通过构造方法创建代理类对象
h是JdkDynamicAopProxy 实现了InvocationHandler接口
JdkDynamicAopProxy中的属性advised是我们的代理工厂ProxyFactory
ProxyFactory封装了各种参数比如被代理类的实例以及advisors
advisor中又封装了增强方法和增强方法的切面表达式。
***/
return cons.newInstance(new Object[]{h});
5.2.1newInstance
public T newInstance(Object ... initargs)
    throws InstantiationException, IllegalAccessException,
           IllegalArgumentException, InvocationTargetException{
    if (!override) {
        if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
            Class<?> caller = Reflection.getCallerClass();
            checkAccess(caller, clazz, null, modifiers);
        }
    }
    if ((clazz.getModifiers() & Modifier.ENUM) != 0)
        throw new IllegalArgumentException
                                ("Cannot reflectively create enum objects");
    ConstructorAccessor ca = constructorAccessor;  
    if (ca == null) {
        ca = acquireConstructorAccessor();
    }
    @SuppressWarnings("unchecked")
    T inst = (T) ca.newInstance(initargs);
    return inst;
}

6.怎么查看代理类$Proxy的代码?

我们可以通过添加JVM运行参数来解决

image.png

然后在虚拟机参数一栏中添加JVM运行参数:-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true

image.png

需要注意的是我这边的测试类是AopTest,大家到时候选择自己的测试类配置就可以了。

JVM运行参数配置完毕后,再执行一下测试类,比如我这里是AopTest,这个时候就会将运行时生成的代理类给保存到com.sun.proxy。

image.png

或者使用 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

 
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import jdk代理.Calculator1;
import jdk代理.Calculator2;
//我们生成的代理类继承了Proxy
//在spring中 Proxy类型的 或者是 接口类型的 都必须使用jdk动态代理哦
public final class $Proxy extends Proxy implements Calculator1, Calculator2 {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m4;
    private static Method m5;
    private static Method m6;
    private static Method m0;

    public $Proxy(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            //可以看到这里把 当前代理对象实例 原始方法  原始方法参数都传递给了
            //InvocationHandler#invoke方法
            //参数this 代理类实例
            //参数m1 当前执行的equals方法
            //参数 new Object[]{var1}   当前执行的方法的参数
            //super是Proxy
            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 int add(int var1, int var2) throws  {
        try {
            return (Integer)super.h.invoke(this, m3, new Object[]{var1, var2});
        } catch (RuntimeException | Error var4) {
            throw var4;
        } catch (Throwable var5) {
            throw new UndeclaredThrowableException(var5);
        }
    }

    public final int sub(int var1, int var2) throws  {
        try {
            return (Integer)super.h.invoke(this, m4, new Object[]{var1, var2});
        } catch (RuntimeException | Error var4) {
            throw var4;
        } catch (Throwable var5) {
            throw new UndeclaredThrowableException(var5);
        }
    }

    public final int mult(int var1, int var2) throws  {
        try {
            return (Integer)super.h.invoke(this, m5, new Object[]{var1, var2});
        } catch (RuntimeException | Error var4) {
            throw var4;
        } catch (Throwable var5) {
            throw new UndeclaredThrowableException(var5);
        }
    }

    public final int div(int var1, int var2) throws  {
        try {
            return (Integer)super.h.invoke(this, m6, new Object[]{var1, var2});
        } catch (RuntimeException | Error var4) {
            throw var4;
        } catch (Throwable var5) {
            throw new UndeclaredThrowableException(var5);
        }
    }

    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("jdk代理.Calculator1").getMethod("add", Integer.TYPE, Integer.TYPE);
            m4 = Class.forName("jdk代理.Calculator1").getMethod("sub", Integer.TYPE, Integer.TYPE);
            m5 = Class.forName("jdk代理.Calculator2").getMethod("mult", Integer.TYPE, Integer.TYPE);
            m6 = Class.forName("jdk代理.Calculator2").getMethod("div", Integer.TYPE, Integer.TYPE);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

可以看到这个构造方法的入参是InvocationHandler类型的,那这个构造方法会在哪里使用呢?

会在之前分析的newProxyInstance()方法中

// 获取代理类中的构造方法
final Constructor<?> cons = cl.getConstructor(constructorParams);
// 使用反射通过构造方法创建代理类对象,注意这里会将回调程序h传递到代理类中
return cons.newInstance(new Object[]{h});

父类的这个构造方法非常简单,其实就是将子类传递过来的InvocationHandler赋值给了h属性,而子类此时传递过来的InvocationHandler其实就是JdkDynamicAopProxy,也就是说此时父类中的这个h属性就是JdkDynamicAopProxy。

创建代理时有下面这么一句代码

public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
    if (config.getAdvisors().length == 0 
    && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
            throw new AopConfigException();
    }
    this.advised = config;
}
/***
this是JdkDynamicAopProxy 实现了InvocationHandler接口
重点JdkDynamicAopProxy中的属性advised
advised是我们的代理工厂ProxyFactory
ProxyFactory封装了各种参数比如被代理类的实例以及advisors
advisor中又封装了增强方法和增强方法的切面表达式。
***/
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);

所以在方法调用的时候需要看JdkDynamicAopProxy的invoke方法,其实是InvocationHandler的invoke方法

public final boolean equals(Object var1) throws  {
    try {
        //可以看到这里把 当前代理对象实例 原始方法  原始方法参数都传递给了
        //InvocationHandler#invoke方法
        //参数this 代理类实例
        //参数m1 当前执行的equals方法
        //参数 new Object[]{var1}   当前执行的方法的参数
        //super是Proxy
        return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
    } catch (RuntimeException | Error var3) {
        throw var3;
    } catch (Throwable var4) {
        throw new UndeclaredThrowableException(var4);
    }
}

直接调用父类h属性的invoke()方法,我们知道现在父类Proxy中的h属性是JdkDynamicAopProxy。

所以只要代理类类的equals方法被调用,那么就会执行JdkDynamicAopProxy类的invoke()方法!

之所以调用代理对象的方法会自动回调到InvocationHandler的invoke()方法。

是因为jdk在生成代理类时,为每个方法都生成了一行 super.h.invoke() 这样的代码。

//可以看到这里把 当前代理对象实例 原始方法  原始方法参数都传递给了
//InvocationHandler#invoke方法
//参数this 代理类实例
//参数m1 当前执行的equals方法
//参数 new Object[]{var1}   当前执行的方法的参数
//super是Proxy
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});

而这个h其实就是一个InvocationHandler,因此才可以回调到InvocationHandler的invoke()方法了。