JDK动态代理使用及相关源码解读

动态代理

概述

之前在实现静态代理时,需要根据实现的接口来自己去定义生成代理类。而 JDK 动态代理运用了 java.lang.reflect.Proxy 类中的方法,想要生成一个类的代理类,只需要自定义一个处理方法执行前后逻辑的 handler,调用 Proxy 类中的生成代理类的方法,就可以得到代理类了,不需要针对不同的接口去自己编写代理类了。

举例

定义代理类和被代理类共同实现的接口

interface Human {
    
    
    String getBelief();

    void eat(String food);
}

定义被代理类 SuperMan

class SuperMan implements Human {
    
    

    @Override
    public String getBelief() {
    
    
        return "I believe I can fly!";
    }

    @Override
    public void eat(String food) {
    
    
        System.out.println("I like to eat " + food);
    }
}

创建一个通用的代理类生产工厂,传入一个对象,可以返回一个它的代理类

class ProxyFactory {
    
    
    // 调用此方法,返回一个代理类的对象,解决1.
    public static Object getProxyInstance(Object obj) {
    
     // obj: 被代理类的对象
        Object instance = Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),
                // 这是实现InvocationHandler接口的自定义类,是一个函数接口
                // 里面只有invoke方法
                (proxy, method, args) -> {
    
    
                    System.out.println("方法调用之前......");
                    // 通过反射调用被代理对象的方法
                    Object o = method.invoke(obj, args);
                    System.out.println("方法调用之后......");
                    return o;
                });
        return instance;
    }
}

newProxyInstance() 中的最后一个参数是一个实现了 InvocationHandler 接口的对象。InvocationHandler 是一个函数接口,具体源码如下

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

当代理类的方法被调用时,代理类就会调用 handler 的 invoke 方法来执行相关逻辑。这样,我们就可以在被代理类执行方法(method.invoke(obj, args))前后来织入我们自己想要执行的逻辑。

测试

public class ProxyTest {
    
    
    @Test
    public void test() {
    
    
        SuperMan superMan = new SuperMan();
        // 获取代理对象
        Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);
        // 调用接口的方法,会自动调用handler中的invoke方法,动态调用同名方法
        proxyInstance.eat("apple");
    }
}

执行结果
在这里插入图片描述
可见在执行被代理对象方法前后,也执行了自定义的逻辑

源码

源码分为两部分,分别是 Proxy 生成代理类的方法和生成好的代理类执行目标方法
注:本文源码对应的 JDK 版本为 15

生成代理类源码

  1. 进入 Proxy.newProxyInstance() 方法

    /**
     * 返回实现给定接口的代理类
     */
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h) {
          
          
        Objects.requireNonNull(h);
    
        final Class<?> caller = System.getSecurityManager() == null
                                    ? null
                                    : Reflection.getCallerClass();
    
        /*
         * 找到用于生成代理类的构造方法
         */
        Constructor<?> cons = getProxyConstructor(caller, loader, interfaces);
    
        return newProxyInstance(caller, cons, h);
    }
    

    关键语句是倒数第二个语句,进入这个方法

  2. Proxy.getProxyConstructor()

    /**
     * 返回代理类的构造方法
     */
    private static Constructor<?> getProxyConstructor(Class<?> caller,
                                                      ClassLoader loader,
                                                      Class<?>... interfaces)
    {
          
          
        // 对接口只有一个的情况进行优化
        if (interfaces.length == 1) {
          
          
            Class<?> intf = interfaces[0];
            if (caller != null) {
          
          
                checkProxyAccess(caller, loader, intf);
            }
            // 向代理cache插入新的proxyBuilder
            return proxyCache.sub(intf).computeIfAbsent(
                loader,
                (ld, clv) -> new ProxyBuilder(ld, clv.key()).build()
            );
        } else {
          
          
            // 对接口数组进行深拷贝
            final Class<?>[] intfsArray = interfaces.clone();
            if (caller != null) {
          
          
                checkProxyAccess(caller, loader, intfsArray);
            }
            // 将数组转换为list
            final List<Class<?>> intfs = Arrays.asList(intfsArray);
            return proxyCache.sub(intfs).computeIfAbsent(
                loader,
                (ld, clv) -> new ProxyBuilder(ld, clv.key()).build()
            );
        }
    }
    

    在 Proxy 类中有个属性 proxyCache,这是一个装有代理类构造器的缓存。第 17 行中,ld 是 class loader,clv 是 class loader value,在这里 clv 的 key 就是被代理类实现的接口 Human

    ProxyBuilder 的匿名对象 new 出来后,进入他的 build() 方法

  3. Proxy.ProxyBuilder.build() 方法

    /**
     * 生成代理类的Class类并返回要求的构造器
     */
    Constructor<?> build() {
          
          
        // 定义代理类的Class类
        Class<?> proxyClass = defineProxyClass(module, interfaces);
        final Constructor<?> cons;
        try {
          
          
            cons = proxyClass.getConstructor(constructorParams);
        } catch (NoSuchMethodException e) {
          
          
            throw new InternalError(e.toString(), e);
        }
        AccessController.doPrivileged(new PrivilegedAction<Void>() {
          
          
            public Void run() {
          
          
                cons.setAccessible(true);
                return null;
            }
        });
        return cons;
    }
    

    第 6 行就是生成代理类 Class 类的语句,进入这个方法

  4. java.lang.reflect.Proxy.ProxyBuilder#defineProxyClass

    /**
     * 生成代理类的Class类
     */
    private static Class<?> defineProxyClass(Module m, List<Class<?>> interfaces) {
          
          
        String proxyPkg = null;     // 代理类所属的package
        int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
    
        /*
         * 记录所有非public接口的package,来保证后面生成的代理类和非public接口所在的package是
         * 一样的。同时也为了验证所有非public的接口都在同一个package下(如果不在一个package,
         * 生成的代理类就无法访问这些接口)
         */
        for (Class<?> intf : interfaces) {
          
          
            int flags = intf.getModifiers();
            if (!Modifier.isPublic(flags)) {
          
          
                accessFlags = Modifier.FINAL;  // non-public, final
                String pkg = intf.getPackageName();
                if (proxyPkg == null) {
          
          
                    proxyPkg = pkg;
                } else if (!pkg.equals(proxyPkg)) {
          
          
                    throw new IllegalArgumentException(
                            "non-public interfaces from different packages");
                }
            }
        }
    
        if (proxyPkg == null) {
          
          
            // 如果所有接口都是public,那么就用默认的package
            proxyPkg = m.isNamed() ? PROXY_PACKAGE_PREFIX + "." + m.getName()
                                   : PROXY_PACKAGE_PREFIX;
        } else if (proxyPkg.isEmpty() && m.isNamed()) {
          
          
            // 如果package名是个空字符串且module不是unnamed,抛出异常
            throw new IllegalArgumentException(
                    "Unnamed package cannot be added to " + m);
        }
    
        if (m.isNamed()) {
          
          
            if (!m.getDescriptor().packages().contains(proxyPkg)) {
          
          
                throw new InternalError(proxyPkg + " not exist in " + m.getName());
            }
        }
    
        /*
         * 生成代理类的名字
         */
        // 由于要生成新的代理类,全局代理类序号加一
        long num = nextUniqueNumber.getAndIncrement();
        String proxyName = proxyPkg.isEmpty()
                                ? proxyClassNamePrefix + num
                                : proxyPkg + "." + proxyClassNamePrefix + num;
    
        ClassLoader loader = getLoader(m);
        trace(proxyName, m, loader, interfaces);
    
        /*
         * 生成代理类
         */
        // 生成代理类的字节码
        byte[] proxyClassFile = ProxyGenerator.generateProxyClass(loader, proxyName, interfaces, accessFlags);
        try {
          
          
            // 根据生成的字节码定义Class类
            Class<?> pc = JLA.defineClass(loader, proxyName, proxyClassFile,
                                          null, "__dynamic_proxy__");
            // 向代理类缓存中添加这个代理类
            reverseProxyCache.sub(pc).putIfAbsent(loader, Boolean.TRUE);
            return pc;
        } catch (ClassFormatError e) {
          
          
            /*
             * A ClassFormatError here means that (barring bugs in the
             * proxy class generation code) there was some other
             * invalid aspect of the arguments supplied to the proxy
             * class creation (such as virtual machine limitations
             * exceeded).
             */
            throw new IllegalArgumentException(e.toString());
        }
    }
    

    首先先确定所有的非 public 的接口是否都在一个包下,以确保后面生成的代理类也在这个包下(否则就无法访问这些接口了)。然后生成代理类的名字,这里代理类的名字的生成规则是代理类统一前缀+序号,这个序号每要生成一个代理类,就用 cas 操作加一。

    第 59 行就是生成代理类字节码的语句,调用的是 ProxyGenerator 类的方法,先看看这个类的类图

    oGLnjH.png

    它继承了 ClassWriter,这里判断它具有生成类字节码文件的功能

  5. java.lang.reflect.ProxyGenerator#generateProxyClass

    static byte[] generateProxyClass(ClassLoader loader,
                                     final String name,	// 之前生成的代理类名字
                                     List<Class<?>> interfaces,
                                     int accessFlags) {
          
          
        // new一个代理类生成器
        ProxyGenerator gen = new ProxyGenerator(loader, name, interfaces, accessFlags);
        // 生成代理类的字节码文件
        final byte[] classFile = gen.generateClassFile();
    
        // ...
    
        return classFile;
    }
    

    进入第 8 行的语句调用的方法

  6. java.lang.reflect.ProxyGenerator#generateClassFile

    private byte[] generateClassFile() {
          
          
        visit(V14, accessFlags, dotToSlash(className), null,
                JLR_PROXY, typeNames(interfaces));
    
        /*
         * 向代理类添加一些通用方法:hashCode, equals, toString
         * 这步在接口方法生成之前执行,是因为如果接口方法有重写这三个Object类里的方法
         * 就可以实现覆盖
         */
        addProxyMethod(hashCodeMethod);
        addProxyMethod(equalsMethod);
        addProxyMethod(toStringMethod);
    
        /*
         * 将所有接口的所有方法加进去
         */
        for (Class<?> intf : interfaces) {
          
          
            for (Method m : intf.getMethods()) {
          
          
                if (!Modifier.isStatic(m.getModifiers())) {
          
          
                    addProxyMethod(m, intf);
                }
            }
        }
    
        /*
         * 检查同名同参方法返回类型是否有冲突
         */
        for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
          
          
            checkReturnTypes(sigmethods);
        }
    
        // 生成构造方法
        generateConstructor();
    
        for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
          
          
            for (ProxyMethod pm : sigmethods) {
          
          
                // 对代理类中的Method对象添加static修饰符
                visitField(Modifier.PRIVATE | Modifier.STATIC, pm.methodFieldName,
                        LJLR_METHOD, null, null);
    
                // 生成代理类执行这个方法的代码
                pm.generateMethod(this, className);
            }
        }
    
        // 生成类的静态代码块,用来初始化那些静态Method对象
        generateStaticInitializer();
    
        return toByteArray();
    }
    

    首先添加默认的 hashCode, equals, toString 三个方法,然后再添加接口的所有方法(实际上是给代理类添加了 Method 对象)。然后生成构造器。由于之前添加方法只是给类添加了 Method 成员变量(之后会给出示例),将这几个变量添加静态修饰符,还需要给代理类生成方法的代码(有代码才能执行)。最后加上静态代码块,用于初始化那几个静态 Method 对象。

  7. 回到第 4 步代码的 60 行。得到字节码后,生成代理类 Class 类,然后向缓存中添加这个代理类。

  8. 回到第 3 步,得到代理类后,得到它的构造器,返回即可

  9. 回到第 2 步,返回得到的构造器

  10. 回到第 1 步的最后一句,执行 newProxyInstance() 方法,其实就是执行以下语句

    return cons.newInstance(new Object[]{
          
          h});
    

    这个构造器只有一个入参,就是之前自定义的 invoke 方法的 handler

生成的字节码文件反汇编

final class $Proxy0 extends Proxy implements Human {
    
    
    // 之前提到的Method对象
    private static Method m0;
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m4;

    // 构造器,入参是InvocaitonHandler类型的
    public $Proxy0(InvocationHandler param1) {
    
    
        super(var1);
    }

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

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

    public final String toString() {
    
    
        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 getBelief() {
    
    
        try {
    
    
            return (String)super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
    
    
            throw var2;
        } catch (Throwable var3) {
    
    
            throw new UndeclaredThrowableException(var3);
        }
    }

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

    static {
    
    
        try {
    
    
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("example.Human").getMethod("getBelief");
            m4 = Class.forName("example.Human").getMethod("eat", Class.forName("java.lang.String"));
        } catch (NoSuchMethodException var2) {
    
    
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
    
    
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

可见,代理类中有静态成员变量,都是 Method 的类型,用于方法被调用时,将这些 Method 对象传入 handler。这些静态 Method 会在静态代码块中被初始化,通过反射的方式获得这些方法。当一个方法被调用是,将这个代理类、对应的 Method 对象以及相应的参数传入 handler 即可。

总结

JDK 动态代理主要分为以下几个步骤

  1. 根据传入的被代理类的类加载器和其实现的接口,生成代理类的字节码文件。包括创建接口方法和 3 个 Object 类的方法的 Method 对象(这些对象命名规范为 m0, m1, m2, …)作为代理类的静态属性、生成方法对应的代码、生成构造器、生成初始化静态属性的静态代码块
  2. 字节码生成完成后,执行构造方法,将用户定义的实现了 InvocationHandler 接口的 handler 对象传入代理类的构造方法中
  3. 执行代理类的某一方法时,代理类调用 handler 的 invoke 方法,其中传入的参数包括目标方法对应的代理类中的 Method 对象(比如在本文中的字节码反汇编代码中,eat 方法对应 m4),完成方法调用和执行

猜你喜欢

转载自blog.csdn.net/sililiu/article/details/121660157