JDKProxy

作者: nafoahnaw | 来源:发表于2018-07-11 16:31 被阅读0次
ContactService.java
public interface ContactService {
    void contact(String userId);
}
ContactServiceImpl.java
public class ContactServiceImpl implements ContactService{
    public void contact(String userId) {
        System.out.println("contact with " + userId);
    }
}
JdkProxy.java
public class JdkProxy {

    public static void main(String args[]){
        final ContactService contactService = new ContactServiceImpl();
        ContactService contactServiceProxy = (ContactService) Proxy
                .newProxyInstance(JdkProxy.class.getClassLoader()
                , new Class[] {ContactService.class}
                , new InvocationHandler() {
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("proxy begin...");
                        String proxySimpleClassName = proxy.getClass().getSimpleName();
                        byte[] proxyClassByteArray = ProxyGenerator.generateProxyClass(
                                proxySimpleClassName, proxy.getClass().getInterfaces());
                        FileOutputStream fos = null;
                        try{
                            fos = new FileOutputStream(proxySimpleClassName + ".class");
                            fos.write(proxyClassByteArray);
                            fos.flush();
                        }finally {
                            if(fos != null){
                                fos.close();
                            }
                        }
                        return method.invoke(contactService, args);
                    }
                });
        contactServiceProxy.contact("nafoahnaw");
    }
}

以上代码关键之一在于代理对象contactServiceProxy是如何生成的
要知道这点必须继续深入源码,java.lang.reflect.Proxy#newProxyInstance的关键步骤

        /*
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass0(loader, intfs);
    /**
     * Generate a proxy class.  Must call the checkProxyAccess method
     * to perform permission checks before calling this.
     */
    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }

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

getProxyClass0方法基于WeakCache实现,WeakCache也是一个类Map的结构

    /**
     * a cache of proxy classes
     */
    private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

通过注释和proxyClassCache我们发现ProxyClassFactory是产生代理对象class类的关键
继续深入java.lang.reflect.Proxy.ProxyClassFactory#apply方法,关键代码如下

            /*
             * Generate the specified proxy class.
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);

这样就根据newProxyInstance方法中给出的interfaces创建出了代理对象,继续回到java.lang.reflect.Proxy#newProxyInstance方法,cl就是contactServiceProxy的class对象,通过cl.getConstructor获取构造函数然后生成对象。

/** parameter types of a proxy class constructor */
    private static final Class<?>[] constructorParams =
        { InvocationHandler.class };
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});

这里其实有点困惑,cl里为什么会存在一个参数为InvocationHandler的构造函数?回到ProxyClassFactory方法

            /*
             * Generate the specified proxy class.
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);

代理对象Class对象的具体类定义由ProxyGenerator.generateProxyClass方法给出,通过走读sun.misc.ProxyGenerator#generateClassFile源码我们可以发现,sun.misc.ProxyGenerator#generateConstructor是此方法给我们生成的代理对象加上了该构造方法,sun.misc.ProxyGenerator#generateClassFile方法为代理对象继承了Proxy类,关键代码如下

                var14.writeInt(-889275714);
                var14.writeShort(0);
                var14.writeShort(49);
                this.cp.write(var14);
                var14.writeShort(this.accessFlags);
                var14.writeShort(this.cp.getClass(dotToSlash(this.className)));
                var14.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));
                var14.writeShort(this.interfaces.length);
private ProxyGenerator.MethodInfo generateConstructor() throws IOException {
        ProxyGenerator.MethodInfo var1 = new ProxyGenerator.MethodInfo("<init>", "(Ljava/lang/reflect/InvocationHandler;)V", 1);
        DataOutputStream var2 = new DataOutputStream(var1.code);
        this.code_aload(0, var2);
        this.code_aload(1, var2);
        var2.writeByte(183);
        var2.writeShort(this.cp.getMethodRef("java/lang/reflect/Proxy", "<init>", "(Ljava/lang/reflect/InvocationHandler;)V"));
        var2.writeByte(177);
        var1.maxStack = 10;
        var1.maxLocals = 2;
        var1.declaredExceptions = new short[0];
        return var1;
    }

那么在运行是生成出来的contactServiceProxy对象究竟长啥样呢,我们可以运行最上面的代码,将contactServiceProxy写入到文件中通过idea反编译来看,关键代码如下

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

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }
static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("service.ContactService").getMethod("contact", Class.forName("java.lang.String"));
            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());
        }
    }
public final void contact(String var1) throws  {
        try {
            //这个h就是我们匿名构造的InvocationHandler,从Proxy类继承而来
            super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

相关文章

  • JDKProxy

    ContactService.java ContactServiceImpl.java JdkProxy.java...

  • spring aop两种实现

    jdk aop UserManager.java 接口 UserManagerImpl.java JdkProxy...

  • Spring动态代理

    Spring生成代理对象的方法有两种: jdkProxy和Cglib,具体使用哪个可以由AopProxyFacto...

  • Spring AOP实现原理

    1.Spring AOP是如何对目标对象的方法进行拦截的? 通过JDKProxy或CGLibProxy动态生成代理...

  • 聊一聊Spring中的代理

    代理的概念本文就不细说了,相信网上的文章很多,动态代理,静态代理,JDKProxy和CGLIB,他们的使用区别等。...

  • Spring源码-AOP(二)-jdkProxy与cglib

    前言 上一篇分享了一些AOP相关的概念,这一篇继续上一篇分享java动态代理的两种实现方式。 1、jdkproxy...

网友评论

      本文标题:JDKProxy

      本文链接:https://www.haomeiwen.com/subject/zpphpftx.html