jdk动态代理初探

1. jdk动态代理创建

首先定义一个接口

public interface Action {
    void doSomething();
}

然后实现接口,即创建被代理对象

public class ActionImpl implements Action {
    @Override
    public void doSomething() {
        System.out.println("do something");
    }
}

接着定义一个调用处理器,实现InvocationHandler接口。

public class Handler implements InvocationHandler {
    private Object target;

    public Handler(Object target){
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //before
        System.out.println("before do something");
        Object result = method.invoke(target, args);
        //after
        System.out.println("after do something");
        //return what you want
        return result;
    }
}

最后,通过Proxy.newProxyInstance方法创建代理对象,以下是测试类

public class ProxyTest {
    public static void main(String[] args) {
        Action action = new ActionImpl();
        InvocationHandler handler = new Handler(action);
        Action actionProxy = (Action) Proxy.newProxyInstance(action.getClass().getClassLoader(), new Class[]{Action.class}, handler);
        actionProxy.doSomething();
    }
}

执行main方法,结果如下


结果.png

2. 代理创建过程初探

查看Proxy.newProxyInstance方法源码(为方便说明,略去一些代码)

public static Object newProxyInstance(ClassLoader loader,Class[] interfaces,
                                          InvocationHandler h) throws IllegalArgumentException{
        final Class[] intfs = interfaces.clone();
        Class cl = getProxyClass0(loader, intfs);
        final Constructor cons = cl.getConstructor(constructorParams);
        final InvocationHandler ih = h;
        if (!Modifier.isPublic(cl.getModifiers())) {
            AccessController.doPrivileged(new PrivilegedAction() {
              public Void run() {
                  cons.setAccessible(true);
                  return null;
              }
          });
        }     
        return cons.newInstance(new Object[]{h});
    }

   由源码可知,该方法首先会通过getProxyClass0获取代理类的类对象,然后通过类对象获取代理类中参数类型为InvocationHandler 的构造器方法,调用该构造器创建代理类实例。
   而getProxyClass0方法首先会去查找是否有指定类加载器加载的代理类实现了指定的接口集合,有则返回,没有则通过ProxyClassFactory创建并加载代理类。

// 若代理的接口集合中有非public的接口,则代理类定义非public的接口所在的包中
//若代理接口均为public,则使用com.sun.proxy作为包名
if (proxyPkg == null) {
    proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
//为代理类生成一个类名
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
//生成代理类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());
}

    可知,代理类的class文件是通过ProxyGenerator.generateProxyClass创建的。

3. 动态代理的调用原理

阅读ProxyGenerator类的源码可以知道,在启动参数中设置

sun.misc.ProxyGenerator.saveGeneratedFiles=true

在项目运行时,生成的代理类class文件将保存在项目中。通过idea反编译,可以看到

package com.sun.proxy;

import com.sh.proxy.Action;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

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

    public $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 doSomething() 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("com.sh.proxy.Action").getMethod("doSomething");
            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());
        }
    }
}

生成的代理类$Proxy0类继承了Proxy类且实现了我们定义的Action接口。将接口中的方法与Object的equals、toString、hashCode都改写成super.h.invoke(this, method, args)的形式。有没有觉得很眼熟,没错,这个正是InvocationHandler接口中定义的invoke方法。而super.h其实就是在代理实例构造时我们传入的调用处理器。

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

看到这,应该就明白了动态代理的调用原理:

首先我们创建的InvocationHandler中保存了被代理对象的引用,在构造代理实例时,将InvocationHandler实例传入代理实例,这样当我们调用代理实例的方法时,其实就是在调用InvocationHandler实例的invoke方法。而在invoke方法中我们可以通过被代理对象的引用实现对被代理对象方法的增强,即实现我们想要的切面逻辑。

你可能感兴趣的:(jdk动态代理初探)