JDK如何实现动态代理

定义接口与需要被代理的类

/**
* 实现类
*/
class TargetImpl implements TargetService {
  @Override
  public void sayHello() {
      System.out.println("hello world");
  }
}

/**
* 需要被代理的接口
*/
public interface TargetService {
  /**
   * 用于jdk代理,必须要定义接口
   */
  void sayHello();
}

如何使用jdk提供的动态代理

/**
 * 对代理的类做增强作用
 */
class MyInvokerHandlerProxy implements InvocationHandler {

    private Object target;

    /**
     * 构造方法
     *
     * @param target 目标对象
     */
    public MyInvokerHandlerProxy(Object target) {
        super();
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 在目标对象的方法执行之前简单的打印一下
        System.out.println("------------------before------------------");
        // 执行目标对象的方法
        Object result = method.invoke(target, args);
        // 在目标对象的方法执行之后简单的打印一下
        System.out.println("-------------------after------------------");
        return result;
    }

    /**
     * 获取目标对象的代理对象。参数this代表着将增强类传入了Proxy
     *
     * @return 代理对象
     */
    public Object getProxy() {
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                target.getClass().getInterfaces(), this);
    }
}

分析jdk的Proxy类

直接进入Proxy的源代码,非必要代码直接省略

    Object Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h){
        /*
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass0(loader, intfs);

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

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

返回的是一个Object对象,三个参数,loader用于jdk生成字节码后加载到jvm。interfaces由于jdk动态代理必须声明接口,在jdk动态代理的实现类上必然实现该接口。h能够进行增强,并且通过反射调用target的方法。

获取class对象(上面代码里面有非常重要的注释,寻找或是生成指定的代理类的class对象),找到Constructor,之后通过反射返回代理的类的实例。

继续分析获取class对象的方法

public class Proxy implements java.io.Serializable{
    /**
     * a cache of proxy classes
     */
    private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        // If the proxy class defined by the given loader implementing
        // the given interfaces exists, this will simply return the cached copy;
        // otherwise, it will create the proxy class via the ProxyClassFactory
        return proxyClassCache.get(loader, interfaces);
    }
}

这里具有迷惑性,jdk注释详细的去解释了这个方法。做了相当多的封装并且加入了cache,注释中已经提到了生成class使用的是ProxyClassFactory。需要有其它的时间来分析WeakCache。

继续进入ProxyClassFactory

 private static final class ProxyClassFactory
        implements BiFunction<ClassLoader, Class<?>[], Class<?>>
    {
        @Override
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
            /*
             * Generate the specified proxy class.
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                throw new IllegalArgumentException(e.toString());
            }
        }
    }

贴出了最重要的步骤。但是ProxyGenerator.generateProxyClass()没有办法看到源代码,defineClass0()是一个native方法,不过通过命名能够看懂这个两个方法主要是做了什么事情,首先生成代理类的字节码,之后加载字节码并返回class对象。ProxyGenerator 这个类能够去openJDK中去看,大概就是通过操作字节码,生成代理类的二进制文件。

分析到这里,其实jdk已经干完了所有事情,但是还是没有办法看到整个代理类是怎么运行的。下面是openJDK 中ProxyGenerator生成字节码后反编译的类。

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

package .demo.wangjq.base.designpattern;

import demo.wangjq.base.designpattern.TargetService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class Service$Proxy0 extends Proxy implements TargetService {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    public Service$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 void sayHello() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    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 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"));
            m3 = Class.forName("demo.wangjq.base.designpattern.TargetService").getMethod("sayHello");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

下面给出main方法

 public static void main(String[] args) {
        TargetImpl targetImpl = new TargetImpl ();
        MyInvokerHandlerProxy myInvokerHandlerProxy = new MyInvokerHandlerProxy(targetImpl );
        /**
         * 获取代理后的对象。
         */
        TargetService targetService = (TargetService ) myInvokerHandlerProxy.getProxy();
        targetService.sayHello();
}

结合上面的 Service$Proxy字节码生成的代理类。能够分析出uml和执行流程。执行流程: main方法中的targetService.sayHello()-> super.h.invoke(this, m3, (Object[])null)-> MyInvokerHandlerProxy.invoke();

在代理类中,继承Proxy,实现了代理类执行的时候是调用了Proxy的InvokerHandler成员变量的invoke,而InvokerHandler实现类是传入到Proxy的MyInvokerHandlerProxy。java无法多继承这也是为什么jdk代理必须要有接口。

UML

以上就是JDK动态代理的所有分析

posted @ 2020-04-29 21:59  coder1993  阅读(318)  评论(0)    收藏  举报