JDK动态代理实现原理

97 阅读2分钟

之前虽然会使用JDK的动态代理,但是有些问题始终没有搞明白。比如说:InvocationHandler的invoke方法是由谁来调用的?代理对象是怎么生成的?今天就搞明白吧。

1 JDK动态代理的使用

接口:
package designpattern.proxy.userproxy;

public interface UserService {
    void add();
}
实现:
package designpattern.proxy.userproxy;

public class UserServiceImpl implements UserService {

    @Override
    public void add() {
        System.out.println("----------add----------");
    }
}
使用实例:
package designpattern.proxy.userproxy;

import sun.misc.ProxyGenerator;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MyInvocationHandler<T> implements InvocationHandler {
    private T target;
    MyInvocationHandler (T o) {
        super();
        this.target = o;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 将代理对象生成字节码到D:\Workspace
        addClassToDisk(proxy.getClass().getName(), target.getClass(), "D:\Workspace\targetProxy.class");

        System.out.println("方法" + method.getName() + "执行前!");
        Object invokeResult = method.invoke(target, args);
        System.out.println("方法" + method.getName() + "执行后!");
        return invokeResult;
    }

    public T getProxy() {
        ClassLoader classLoader = target.getClass().getClassLoader();
        Class<?>[] intfs = target.getClass().getInterfaces();
        return (T) Proxy.newProxyInstance(classLoader, intfs, this);
    }

    private void addClassToDisk(String className, Class<?> cl, String path) {
        // JDK底层即使通过这个方法生成代理对象的.class字节码文件
        byte[] bytes = ProxyGenerator.generateProxyClass(className, cl.getInterfaces());
        FileOutputStream outputStream = null;
        try {
            outputStream = new FileOutputStream(path);
            outputStream.write(bytes);
            outputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

2 JDK生成代理对象类的.class字节码文件

JDK底层通过ProxyGenerator.generateProxyClass(className, cl.getInterfaces())创建代理对象类的.class字节码文件
image.png

测试用例:
@org.junit.Test
public void test_JDKProxy() {
    // 实例化目标对象
    UserService userService = new UserServiceImpl();
    // 实例化InvocationHandler,传入被代理的目标对象
    MyInvocationHandler<UserService> myInvocationHandler = new MyInvocationHandler(userService);

    // 根据传入的被代理对象,生成代理对象
    UserService userServiceProxy = myInvocationHandler.getProxy();
    System.out.println(Proxy.isProxyClass(userServiceProxy.getClass()));
    // 调用代理对象的方法
    userServiceProxy.add();
}

3 动态代理类

动态代理对象类的字节码(.class文件)反编译后:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.sun.proxy;

import designpattern.proxy.userproxy.UserService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy4 extends Proxy implements UserService {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    // 通过这个构造方法创建代理对象实例
    public $Proxy4(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 add() throws  {
        try {
            super.h.invoke(this, m3, (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("designpattern.proxy.userproxy.UserService").getMethod("add");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

生成的代理对象实现了接口的所有方法(接口定义的add()方法和equals(Object var1)、hashCode()、toString())。调用代理对象实现的所有接口方法,都会交给InvocationHandler.invoke()方法处理。

4 生成代理对象

代理对象类的class对象创建代理对象,构造方法的参数即为传进来的InvocationHandler,每个代理对象都从父类Proxy继承了一个InvocationHandler image.png