java动态代理

1.什么是动态代理

  动态代理,就是在运行时,基于一个类,动态生成一个代理类,以增强被代理类的功能。最著名的动态代理就是AOP,在被代理类的方法调用开始之前和调用结束之后,做一些通用的工作,比如打印日志、捕获异常等等。

  当然有动态代理就有静态代理(设计模式中的代理模式)。

2.一个动态代理使用的实例

接口:

public interface Worker {
    void work();
}

接口实现的类:

public class WorkerImpl implements Worker {

    public void work() {
        System.out.println("我正在工作!");
    }

    public void work2() {
        System.out.println("我正在工作2!");
    }
}

 

动态生成的类:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class DynamicWorker implements InvocationHandler {

    private Object obj;

    public DynamicWorker(Object obj) {
        this.obj = obj;
    }

    public DynamicWorker(Class clazz) throws Exception {
        this(clazz.newInstance());
    }

    public DynamicWorker(String className) throws Exception {
        this(Class.forName(className));
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("开始工作之前,我要准备工具!");
        method.invoke(obj, args);
        System.out.println("完成工作之后,收拾好工具!");
        return null;
    }
}

 

测试类:

import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Proxy;

public class Main {

    public static void main(String[] args) throws Exception {
        String className = WorkerImpl.class.getName();
        DynamicWorker dynamicWorker = new DynamicWorker(className);

        Worker worker = (Worker)Proxy.newProxyInstance(WorkerImpl.class.getClassLoader(), WorkerImpl.class.getInterfaces(), dynamicWorker);
        worker.work();
        worker.work2();

        System.out.println("worker是不是WorkerImpl的实例--->" + (worker instanceof WorkerImpl));

        System.out.println("worker对应的类为--->" + worker.getClass().getSimpleName());

        System.out.println("worker继承的父类为--->" + worker.getClass().getSuperclass().getSimpleName());

        System.out.println("worker实现的接口为--->" + StringUtils.join(worker.getClass().getInterfaces(), ","));

        System.out.println("worker所有的属性为--->\n" + StringUtils.join(worker.getClass().getDeclaredFields(), "\n"));

        System.out.println("worker所有的方法为--->\n" + StringUtils.join(worker.getClass().getDeclaredMethods(), "\n"));
    }
}

运行的结果:

开始工作之前,我要准备工具!
我正在工作!
完成工作之后,收拾好工具!
开始工作之前,我要准备工具!
我正在工作2!
完成工作之后,收拾好工具!
worker是不是WorkerImpl的实例--->false
worker对应的类为--->$Proxy0
worker继承的父类为--->Proxy
worker实现的接口为--->interface com.taobao.zhenge.java.proxy.Worker
worker所有的属性为--->
private static java.lang.reflect.Method com.sun.proxy.$Proxy0.m1
private static java.lang.reflect.Method com.sun.proxy.$Proxy0.m3
private static java.lang.reflect.Method com.sun.proxy.$Proxy0.m4
private static java.lang.reflect.Method com.sun.proxy.$Proxy0.m2
private static java.lang.reflect.Method com.sun.proxy.$Proxy0.m0
worker所有的方法为--->
public final boolean com.sun.proxy.$Proxy0.equals(java.lang.Object)
public final java.lang.String com.sun.proxy.$Proxy0.toString()
public final int com.sun.proxy.$Proxy0.hashCode()
public final void com.sun.proxy.$Proxy0.work()
public final void com.sun.proxy.$Proxy0.work2()

 

从上面的例子可以看出,动态代理可以实现什么样的功能。

总结如下:

1.两个重要的类:Proxy和InvocationHandler

  Proxy:生成代理类的入口,一些具体测策略和逻辑都在这个类中

  InvocationHandler:用来对被代理类做增强处理,需要引用被代理类的实例(一般通过反射获取)

2.动态代理是基于接口做的代理

  1)被代理类必须要实现接口

  2)代理类只能增强接口对应的方法(可以有多个方法),不能增加非接口方法

 

3.动态代理生成的类到底是什么样子的

jdk中动态代理底层是调用ProxyGenerator.generateProxyClass去生成class文件的字节码的,如下代码所示:

mport sun.misc.ProxyGenerator;

import java.io.FileOutputStream;
import java.lang.reflect.Modifier;

public class GenerateClass {

    public static void main(String[] args) throws Exception {
        String className = "com.taobao.test.ProxyClass";
        Class[] interfaces = new Class[]{Worker.class};
        int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

        byte[] classByte = ProxyGenerator.generateProxyClass(className, interfaces, accessFlags);

        FileOutputStream fos = new FileOutputStream("ProxyClass");
        fos.write(classByte);
        fos.close();
    }
}

三个参数中:

  className:生成代理类的完整类名

  interfaces:代理类实现的接口(这也说明,java的动态代理只能代理实现了接口的代理类)

  accessFlags:类的修饰符,public等

最后将生成的class字节码保存到文件中。

 

反编译后得到的代码:

package com.taobao.test;

import com.taobao.test.Worker;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class ProxyClass extends Proxy implements Worker {

   private static Method m1;
   private static Method m3;
   private static Method m4;
   private static Method m2;
   private static Method m0;


   public ProxyClass(InvocationHandler var1) throws  {
      super(var1);
   }

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

   public final void work() throws  {
      try {
         super.h.invoke(this, m3, (Object[])null);
      } catch (RuntimeException | Error var2) {
         throw var2;
      } catch (Throwable var3) {
         throw new UndeclaredThrowableException(var3);
      }
   }

   public final void work2() throws  {
      try {
         super.h.invoke(this, m4, (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)).intValue();
      } catch (RuntimeException | Error var2) {
         throw var2;
      } catch (Throwable var3) {
         throw new UndeclaredThrowableException(var3);
      }
   }

   static {
      try {
         m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
         m3 = Class.forName("com.taobao.test.Worker").getMethod("work", new Class[0]);
         m4 = Class.forName("com.taobao.test.Worker").getMethod("work2", new Class[0]);
         m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
         m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      } catch (NoSuchMethodException var2) {
         throw new NoSuchMethodError(var2.getMessage());
      } catch (ClassNotFoundException var3) {
         throw new NoClassDefFoundError(var3.getMessage());
      }
   }
}

InvocationHandler在哪里?动态代理类继承自Proxy,Proxy中引用了InvocationHandler。

从反编译得到的结果可以很清晰的看出动态代理生成类的结构。

 

4.动态代理源码解析

上面以及提到动态代理涉及到两个核心类,Proxy和InvocationHandler,其中InvocationHandler非常简单,用于增加代理类的功能,需要根据自己的实际需求去扩展,这里主要解析Proxy是怎样生成动态代理类的,从入口(Proxy.newProxyInstance)开始:

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);
    }

    /*
     * Look up or generate the designated proxy class.
     */
    Class<?> cl = getProxyClass0(loader, intfs);

    /*
     * Invoke its constructor with the designated invocation handler.
     */
    try {
        if (sm != null) {
            checkNewProxyPermission(Reflection.getCallerClass(), cl);
        }

        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;
                }
            });
        }
        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);
    }
}

接口的三个参数:

  loader:代理类对应的ClassLoader

  interfaces:代理类实现的接口

  h:InvocationHandler,具体实现了如何增强代理类

整个过程大致可以分成三个步骤:

  1.根据loader和interfaces生成对应的Class对象

  Class对象的生成逻辑全部在ProxyClassFactory中,底层就是调用ProxyGenerator.generateProxyClass去生成class文件的字节码

  2.找到Class对象中以InvocationHandler为参数的构造方法

  3.使用反射生成对应的对象

关于源码的详细细节,可以参考这篇文章

 

posted @ 2018-06-18 01:50  zhenge2016  阅读(125)  评论(0)    收藏  举报