JAVA动态代理用法与实现过程

来源:互联网 发布:sql insert 单引号 编辑:程序博客网 时间:2024/05/21 17:41

JAVA动态代理用法与实现过程

本文包括jdk动态代理的用法以及源码实现过程


首先看看jdk动态代理的用法

动态代理涉及到两个类:
Proxy类和InvocationHandler接口

1,编写被代理类实现的接口

public interface User {    void add();}

2,被代理类实现类

public class UserImpl implements User {    @Override    public void add() {        System.out.println("**************add*************");    }}

3,编写自己的InvocationHandler

import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;/** * Created by FUPENG581 on 2016-07-29. */public class MyInvocation implements InvocationHandler {    private Object target;    public MyInvocation(Object target) {        this.target = target;    }    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        System.out.println("************before**************");        Object obj = method.invoke(target, args);        System.out.println("************after**************");        return obj;    }    public Object getProxy() {        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),                target.getClass().getInterfaces(), this);    }    public void print() {        Class cl = Proxy.getProxyClass(Thread.currentThread().getContextClassLoader(),                target.getClass().getInterfaces());    }}

在该实现中:
- 重写InvocationHandler的invoke方法,并添加需要的前置和后置处理。
- 使用Proxy类的静态方法newProxyInstance()生成代理对象,其中该方法的接受参数:

- ClassLoader loader表示当前使用到的appClassloader。- Class<?>[] interfaces表示目标对象实现的一组接口。- InvocationHandler h表示当前的InvocationHandler实现实例对象。

4,编写测试类

public class Test {    public static void main(String[] args) {        User user = new UserImpl();        MyInvocation myInvocation = new MyInvocation(user);        User proxy = (User) myInvocation.getProxy();        proxy.add();    }}

执行输出结果:

************before****************************add*************************after**************

来看看动态代理的具体过程

  1. 使用被代理对象创建InvocationHandler对象实例
  2. 生成代理对象实例
    • 生成proxy代理对象的字节码文件,并创建proxy的类对象
    • 根据proxy的类对象使用反射创建proxy对象实例
  3. 在代理对象实例上调用目标方法(就是调用invoke的过程)

生成proxy字节码文件以及反射创建proxy实例对象的过程

1,Proxy.getProxyClass()方法
源码如下:

public static Object newProxyInstance(ClassLoader loader,                      Class<?>[] interfaces,                      InvocationHandler h)    throws IllegalArgumentException    {    if (h == null) {        throw new NullPointerException();    }    /*     * Look up or generate the designated proxy class.     * **1,根据传递进来的classloader和接口创建代理对象proxy的类对象**     */    Class cl = getProxyClass(loader, interfaces);    /*     * Invoke its constructor with the designated invocation handler.     * **2,使用proxy类对象反射创建proxy实例对象**     */    try {        Constructor cons = cl.getConstructor(constructorParams);        return (Object) cons.newInstance(new Object[] { h });    } catch (NoSuchMethodException e) {        throw new InternalError(e.toString());    } catch (IllegalAccessException e) {        throw new InternalError(e.toString());    } catch (InstantiationException e) {        throw new InternalError(e.toString());    } catch (InvocationTargetException e) {        throw new InternalError(e.toString());    }    }

该方法根据当前应用程序类加载器以及目标对象所实现的一组接口创建proxy类对象;
并使用当前的InvocationHandler实例对象创建proxy实例对象。

2,我们来看看Class cl = getProxyClass(loader, interfaces)方法

   public static Class<?> getProxyClass(ClassLoader loader,                                          Class<?>... interfaces)    throws IllegalArgumentException    {    if (interfaces.length > 65535) {        throw new IllegalArgumentException("interface limit exceeded");    }    Class proxyClass = null;    String[] interfaceNames = new String[interfaces.length];    Set interfaceSet = new HashSet();   // for detecting duplicates    for (int i = 0; i < interfaces.length; i++) {        String interfaceName = interfaces[i].getName();        Class interfaceClass = null;        try {        interfaceClass = Class.forName(interfaceName, false, loader);        } catch (ClassNotFoundException e) {        }        if (interfaceClass != interfaces[i]) {        throw new IllegalArgumentException(            interfaces[i] + " is not visible from class loader");        }        if (!interfaceClass.isInterface()) {        throw new IllegalArgumentException(            interfaceClass.getName() + " is not an interface");        }        if (interfaceSet.contains(interfaceClass)) {        throw new IllegalArgumentException(            "repeated interface: " + interfaceClass.getName());        }        interfaceSet.add(interfaceClass);        interfaceNames[i] = interfaceName;    }    Object key = Arrays.asList(interfaceNames);    Map cache;    synchronized (loaderToCache) {        cache = (Map) loaderToCache.get(loader);        if (cache == null) {        cache = new HashMap();        loaderToCache.put(loader, cache);        }    }    synchronized (cache) {        do {        Object value = cache.get(key);        if (value instanceof Reference) {            proxyClass = (Class) ((Reference) value).get();        }        if (proxyClass != null) {            return proxyClass;        } else if (value == pendingGenerationMarker) {            try {            cache.wait();            } catch (InterruptedException e) {            }            continue;        } else {            cache.put(key, pendingGenerationMarker);            break;        }        } while (true);    }    try {        String proxyPkg = null; // package to define proxy class in        for (int i = 0; i < interfaces.length; i++) {        int flags = interfaces[i].getModifiers();        if (!Modifier.isPublic(flags)) {            String name = interfaces[i].getName();            int n = name.lastIndexOf('.');            String pkg = ((n == -1) ? "" : name.substring(0, n + 1));            if (proxyPkg == null) {            proxyPkg = pkg;            } else if (!pkg.equals(proxyPkg)) {            throw new IllegalArgumentException(                "non-public interfaces from different packages");            }        }        }        if (proxyPkg == null) { // if no non-public proxy interfaces,        proxyPkg = "";      // use the unnamed package        }        {        long num;        synchronized (nextUniqueNumberLock) {            num = nextUniqueNumber++;        }        String proxyName = proxyPkg + proxyClassNamePrefix + num;        /*         * Generate the specified proxy class.         * **前面可以当做是验证部分的代码**         * **这里是最重要的地方**         */         //1,生成proxy代理类的字节码文件        byte[] proxyClassFile = ProxyGenerator.generateProxyClass(            proxyName, interfaces);        try {        //2,根据proxy代理类的字节码文件创建proxy代理类对象            proxyClass = defineClass0(loader, proxyName,            proxyClassFile, 0, proxyClassFile.length);        } catch (ClassFormatError e) {            throw new IllegalArgumentException(e.toString());        }        }        // add to set of all generated proxy classes, for isProxyClass        proxyClasses.put(proxyClass, null);    } finally {        synchronized (cache) {        if (proxyClass != null) {            cache.put(key, new WeakReference(proxyClass));        } else {            cache.remove(key);        }        cache.notifyAll();        }    }    return proxyClass;    }

在该方法中主要就是两件事:

  • 生成proxy代理类的字节码文件。
  • 根据字节码文件创建proxy的类对象。

3,我们在来看一看生成的proxy代理类的字节码文件
使用

System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

来查看保存的代理类字节码文件,路径默认为项目路径下com/sun/proxy

import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.lang.reflect.UndeclaredThrowableException;public final class $Proxy11  extends Proxy  implements User{  private static Method m1;  private static Method m3;  private static Method m0;  private static Method m2;  public $Proxy11(InvocationHandler paramInvocationHandler)    throws   {    super(paramInvocationHandler);  }  public final boolean equals(Object paramObject)    throws   {    try    {      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();    }    catch (Error|RuntimeException localError)    {      throw localError;    }    catch (Throwable localThrowable)    {      throw new UndeclaredThrowableException(localThrowable);    }  }  public final void add()    throws   {    try    {      this.h.invoke(this, m3, null);      return;    }    catch (Error|RuntimeException localError)    {      throw localError;    }    catch (Throwable localThrowable)    {      throw new UndeclaredThrowableException(localThrowable);    }  }  public final int hashCode()    throws   {    try    {      return ((Integer)this.h.invoke(this, m0, null)).intValue();    }    catch (Error|RuntimeException localError)    {      throw localError;    }    catch (Throwable localThrowable)    {      throw new UndeclaredThrowableException(localThrowable);    }  }  public final String toString()    throws   {    try    {      return (String)this.h.invoke(this, m2, null);    }    catch (Error|RuntimeException localError)    {      throw localError;    }    catch (Throwable localThrowable)    {      throw new UndeclaredThrowableException(localThrowable);    }  }  static  {    try    {      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });      m3 = Class.forName("User").getMethod("add", new Class[0]);      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);      return;    }    catch (NoSuchMethodException localNoSuchMethodException)    {      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());    }    catch (ClassNotFoundException localClassNotFoundException)    {      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());    }  }}

生成的代理类继承Proxy类并实现User接口,这里也是为什么jdk动态代理是基于接口的了原因了。在proxy代理类中的 public final void add()方法会去调用从Proxy类继承过来的InvocationHandler(即自定义的实现类)成员变量的invoke方法。

0 0