29.AOP源码之JDK动态代理


highlight: arduino-light

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

java @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对象,然后再获取构造方法,最后通过构造方法创建了代理类的对象。 ```java /* 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动态生成字节码文件

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

```java // 初始化proxyClassCache,注意它的value是ProxyClassFactory类型 private static final WeakCache [], 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构建实例

java /*** 使用反射通过构造方法创建代理类对象 h是JdkDynamicAopProxy 实现了InvocationHandler接口 JdkDynamicAopProxy中的属性advised是我们的代理工厂ProxyFactory ProxyFactory封装了各种参数比如被代理类的实例以及advisors advisor中又封装了增强方法和增强方法的切面表达式。 ***/ return cons.newInstance(new Object[]{h});

5.2.1newInstance

java 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");

```java

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()方法中 md // 获取代理类中的构造方法 final Constructor<?> cons = cl.getConstructor(constructorParams); // 使用反射通过构造方法创建代理类对象,注意这里会将回调程序h传递到代理类中 return cons.newInstance(new Object[]{h}); 父类的这个构造方法非常简单,其实就是将子类传递过来的InvocationHandler赋值给了h属性,而子类此时传递过来的InvocationHandler其实就是JdkDynamicAopProxy,也就是说此时父类中的这个h属性就是JdkDynamicAopProxy。

创建代理时有下面这么一句代码 java 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方法 java 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() 这样的代码。 java //可以看到这里把 当前代理对象实例 原始方法 原始方法参数都传递给了 //InvocationHandler#invoke方法 //参数this 代理类实例 //参数m1 当前执行的equals方法 //参数 new Object[]{var1}   当前执行的方法的参数 //super是Proxy return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); 而这个h其实就是一个InvocationHandler,因此才可以回调到InvocationHandler的invoke()方法了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值