jdk动态代理的简单原理

首先看看代理模式的基本类图:此图来源于:https://juejin.im/post/5c1ca8df6fb9a049b347f55c

在这里插入图片描述

我们最主要的目的是调用RealSubject的request方法,但是在实际过程中,我们可能需要在这个方法之前前后做一些别的逻辑处理,为了不做代码侵入或者有些时候我们根本没有办法修改RealSubject的源码,这个时候采用代理模式就非常有效,通过创建一个代理类Proxy,然后使用这个类调用真实类RealSubject的request方法

本文主要是想讲讲jdk动态代理的基本原理,为什么我们代理类实现了InvocationHandler接口的invoke()方法后,然后通过Proxy.newInstance(loader, interface[], realSubject)就能实现调用,内部具体是怎么实现调用的,我们并没调用invoke方法不是?

首先还是看看简单样例代码

public interface TestImp {
    void test();
}


public class TestImpl implements TestImp {

    @Override
    public void test() {
        System.out.println("test Handler impl");
    }
}

public class TestHandler implements InvocationHandler {
    private Object object;

    public TestHandler(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object res = method.invoke(object, args);
        after();
        return res;
    }

    public void before(){
        System.out.println("testImp before");
    }

    public void after(){
        System.out.println("testImp after");
    }
}

//测试类
public class Test {
    public static void main(String[] args) throws InterruptedException {
        TestImp testImp = new TestImpl();
        TestHandler handler = new TestHandler(testImp);
        TestImp imp = (TestImp) Proxy.newProxyInstance(TestImp.class.getClassLoader(), TestImpl.class.getInterfaces(), handler);
        ProxyUtils.generateClassFile(testImp.getClass(), "$Proxy1");
            imp.test();
    }
}


//这段是最后生成代理类的test()方法,后边会说明这段代码是怎么生成出来的
public final void test() throws  {
    try {
        super.h.invoke(this, m3, (Object[])null);
    } catch (RuntimeException | Error var2) {
        throw var2;
    } catch (Throwable var3) {
        throw new UndeclaredThrowableException(var3);
    }
}

//这段代码是网上找的,用于答应生成的代理类信息
//来源于:https://juejin.im/post/5c1ca8df6fb9a049b347f55c
public class ProxyUtils {
    /**
     * 将根据类信息动态生成的二进制字节码保存到硬盘中,默认的是clazz目录下
     * params: clazz 需要生成动态代理类的类
     * proxyName: 为动态生成的代理类的名称
     */
    public static void generateClassFile(Class clazz, String proxyName) {
        // 根据类信息和提供的代理类名称,生成字节码
        byte[] classFile = ProxyGenerator.generateProxyClass(proxyName, clazz.getInterfaces());
        String paths = clazz.getResource(".").getPath();
        System.out.println(paths);
        FileOutputStream out = null;
        try {
            //保留到硬盘中
            out = new FileOutputStream(paths + proxyName + ".class");
            out.write(classFile);
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

以上代码为什么这么写不解释,我们的目的是看看Proxy.newProxyInstance(TestImp.class.getClassLoader(), TestImpl.class.getInterfaces(), handler);这段代码的内部实现

其实这段代码意思很明确,但是具体内部实现细节我们还是不知道,只是它告诉我们这里会生成一个我们传入的具体需要代理的实现类的代理类对象出来

就是身材上图中RealSubject的一个代理类对象出来

然后通过构造方法传入我们实现的InvocationHander对象,然后创建除代理对象实例,

其实我们最关心就是这个代理对象类是怎么创建出来的,

Class<?> cl = getProxyClass0(loader, intfs);这才是核心

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        //检查handler参数不能为空,
        Objects.requireNonNull(h);
        //克隆一份具体实现类的class对象
        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.
         * 调用handler的构造构造方法
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            //拿到构造方法,具体实现类的,这个地方也是关键呀
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            //将我们自定以的handler赋值给ih
            final InvocationHandler ih = h;
            //判断生成的代理是不是public的,如果不是将设置构造方法accessible
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            //生成新的实例返回, 这个地方值得注意了,需要传入一个参数,这个蚕食是InvocationHandler数组
            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);
        }
    }

代理类Class生成方法,但是这里也只是一个方法,并不是我们实际关心的地方

return proxyClassCache.get(loader, interfaces);继续深入

    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        //loader: 我们定义的接口的类加载器,
        //interfaces 表示这个接口的具体实现类

        //具体实现类数组的长度不能大于65535
        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);
    }

proxyClassCache 是一个WeakCache, 内部有两个核型属性;

public WeakCache(BiFunction<K, P, ?> subKeyFactory,
                 BiFunction<K, P, V> valueFactory) {
    this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
    this.valueFactory = Objects.requireNonNull(valueFactory);
}

最后其实我们需要的就是valueFactory属性的解析

首先说一下缓存结构,这个map就是用于对loader生成的Class进行缓存的,所以第一个Object表示的是ClassLoader, 而第二个map用户存储具体生成的Class信息,而第二个Object是根据interface生成的subKey,Supplier就是最后我们需要解析的,我们Class也是通过这个Supplier的get()方法得到的,后边对于缓存的代码不解释了,直接去看Class身材的核心代码,不过这部分代码oracle公司并没有开源

private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map
    = new ConcurrentHashMap<>();
public V get(K key, P parameter) {
        Objects.requireNonNull(parameter);

        //
        expungeStaleEntries();

        //拿到缓存
        //CacheKey 是weakReference的继承类,
        //这里如果key == null ,那么返回一个object对象回来
        //否则创建一个新的CacheKey对象回来
        Object cacheKey = CacheKey.valueOf(key, refQueue);

        // lazily install the 2nd level valuesMap for the particular cacheKey
        ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
        //如果当前类加载器没有进行缓存,那么就创建一个新的ConcurrentHashMap对该类加载的类进行缓存
        if (valuesMap == null) {
            ConcurrentMap<Object, Supplier<V>> oldValuesMap
                = map.putIfAbsent(cacheKey,
                                  valuesMap = new ConcurrentHashMap<>());
            if (oldValuesMap != null) {
                valuesMap = oldValuesMap;
            }
        }

        // create subKey and retrieve the possible Supplier<V> stored by that
        // subKey from valuesMap
        //subKeyFactory: new KeyFactory()
        //key 传入进去没有作用, subKey更加实现实现类的不同,分别是Key1, Key2, Key0 或者keyX
        //这些Key都是reference的实现
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));

        //判断在缓存(ConcurrentHashMap)是否存在当前代理类具体实现类的缓存,
        //如果存在缓存, 那么可以直接通过supplier.get()拿到我们最终需要的代理代理实现类
        Supplier<V> supplier = valuesMap.get(subKey);
        Factory factory = null;

        while (true) {
            //如果缓存存在,那么直接拿到这个缓存的代理对象类返回
            if (supplier != null) {
                // supplier might be a Factory or a CacheValue<V> instance
                V value = supplier.get();
                if (value != null) {
                    return value;
                }
            }
            // else no supplier in cache
            // or a supplier that returned null (could be a cleared CacheValue
            // or a Factory that wasn't successful in installing the CacheValue)

            //如果缓存不存在,这里创建一个Factory用户生成代理实现类,内部通过ProxyClassFacotry具体实类生成
            // lazily construct a Factory
            if (factory == null) {
                //key 类加载器,subKey是实现类转换得到的key, patameter实现类 , valuesMap是代理实现类的hashMap缓存
                factory = new Factory(key, parameter, subKey, valuesMap);
            }

            //如果supplier为空,也就说当前还没有缓存,那么就将刚才生成缓存对象赋值给supplier
            if (supplier == null) {
                //将factory放入到缓存map中,如果得到的supplier,说明真的没有缓存,这个时候就可以进行赋值了
                //这里这样可以有效的避免多线程安全问题
                supplier = valuesMap.putIfAbsent(subKey, factory);
                if (supplier == null) {
                    // successfully installed Factory
                    supplier = factory;
                }
                // else retry with winning supplier
            } else {
                //当上边的supplier不为空的时候,但有没有拿到缓存的代理实现类,那么就需要进行缓存更换
                if (valuesMap.replace(subKey, supplier, factory)) {
                    // successfully replaced
                    // cleared CacheEntry / unsuccessful Factory
                    // with our Factory
                    supplier = factory;
                } else {
                    // retry with current supplier
                    supplier = valuesMap.get(subKey);
                }
            }
        }
    }

ProxyClassFactory类是WeakCache中两个核心属性之一,最后生成Class便是从它开始进入的,而缓存也是着这个方法的apply方法实现的,其实有点不明白,说是缓存,但是好像并没有做大,没错都会调用这个apply方法

byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags); 字节码生成方法入口

private static final class ProxyClassFactory
    implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
    // prefix for all proxy class names
    private static final String proxyClassNamePrefix = "$Proxy";

    // next number to use for generation of unique proxy class names
    private static final AtomicLong nextUniqueNumber = new AtomicLong();

    @Override
    public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

        Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
        for (Class<?> intf : interfaces) {
            /*
             * Verify that the class loader resolves the name of this
             * interface to the same Class object.
             */
            Class<?> interfaceClass = null;
            try {
                //拿到具体实现类的类class对象
                interfaceClass = Class.forName(intf.getName(), false, loader);
            } catch (ClassNotFoundException e) {
            }
            if (interfaceClass != intf) {
                throw new IllegalArgumentException(
                    intf + " is not visible from class loader");
            }
            /*
             * Verify that the Class object actually represents an
             * interface.
             * 验证是不是一个接口,如果不是,那么就抛出一样,表示他没有实现一个接口
             */
            if (!interfaceClass.isInterface()) {
                throw new IllegalArgumentException(
                    interfaceClass.getName() + " is not an interface");
            }
            /*
             * Verify that this interface is not a duplicate.
             * 不能重复操作
             */
            if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                throw new IllegalArgumentException(
                    "repeated interface: " + interfaceClass.getName());
            }
        }

        //代理类包名
        String proxyPkg = null;     // package to define proxy class in
        //类访问表示,这个可以接口深入理解jvm中类加载章节进行理解,表示为public final
        int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

        /*
         * Record the package of a non-public proxy interface so that the
         * proxy class will be defined in the same package.  Verify that
         * all non-public proxy interfaces are in the same package.
         */
        for (Class<?> intf : interfaces) {
            int flags = intf.getModifiers();

            //判断实现类是不是public的,如果不是进行如下操作
            if (!Modifier.isPublic(flags)) {
                //如果不是public,那么将访问表示直接调整为final
                accessFlags = Modifier.FINAL;
                //拿到类名称
                String name = intf.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");
                }
            }
        }

        //如果没有拿到包名称, 那么就使用默认的包名称
        //com.sun.proxy
        if (proxyPkg == null) {
            // if no non-public proxy interfaces, use com.sun.proxy package
            proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
        }

        /*
         * Choose a name for the proxy class to generate.
         * 拿到生成代理类的名称, $Proxy + x
         */
        long num = nextUniqueNumber.getAndIncrement();
        //代理类名称
        String proxyName = proxyPkg + proxyClassNamePrefix + num;

        /*
         * Generate the specified proxy class.
         * 生成代理类的字节码,
         * 内部细节:
         */
        byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
            proxyName, interfaces, accessFlags);

        try {
            //返回定义的类
            return defineClass0(loader, proxyName,
                                proxyClassFile, 0, proxyClassFile.length);
        } catch (ClassFormatError e) {
            /*
             * A ClassFormatError here means that (barring bugs in the
             * proxy class generation code) there was some other
             * invalid aspect of the arguments supplied to the proxy
             * class creation (such as virtual machine limitations
             * exceeded).
             */
            throw new IllegalArgumentException(e.toString());
        }
    }
}

最后调用ProxyGenerator方法的generateClassFile方法,生成我们需要的Class字节码,从这个方法中可以找到有关这个代理类的构造方法,需要传入一个InvocationHandler实例

还有一个更为重要的方法就是generateMethod(),这个方法可以才是核心中核心,其实它就是一个方法生成方法,但是就是在这个方法中定义我我们调用的逻辑为

super.h.invoke(this, m3, (Object[])null);

private byte[] generateClassFile() {
    this.addProxyMethod(hashCodeMethod, Object.class);
    this.addProxyMethod(equalsMethod, Object.class);
    this.addProxyMethod(toStringMethod, Object.class);
    Class[] var1 = this.interfaces;
    int var2 = var1.length;

    int var3;
    Class var4;
    for(var3 = 0; var3 < var2; ++var3) {
        var4 = var1[var3];
        Method[] var5 = var4.getMethods();
        int var6 = var5.length;

        for(int var7 = 0; var7 < var6; ++var7) {
            Method var8 = var5[var7];
            this.addProxyMethod(var8, var4);
        }
    }

    Iterator var11 = this.proxyMethods.values().iterator();

    List var12;
    while(var11.hasNext()) {
        var12 = (List)var11.next();
        checkReturnTypes(var12);
    }

    Iterator var15;
    //添加构造方法,进入这个方法,我们可以看到构造方法需要传入InvocationHandler对象数组,然后最开是我们的newInstance方法中传入的InvocationHandler对象也就会被用到这个构造方法中
    try {
        this.methods.add(this.generateConstructor());
        var11 = this.proxyMethods.values().iterator();

        while(var11.hasNext()) {
            var12 = (List)var11.next();
            var15 = var12.iterator();

            while(var15.hasNext()) {
                ProxyGenerator.ProxyMethod var16 = (ProxyGenerator.ProxyMethod)var15.next();
                this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName, "Ljava/lang/reflect/Method;", 10));
                this.methods.add(var16.generateMethod());
            }
        }

        this.methods.add(this.generateStaticInitializer());
    } catch (IOException var10) {
        throw new InternalError("unexpected I/O Exception", var10);
    }

    if (this.methods.size() > 65535) {
        throw new IllegalArgumentException("method limit exceeded");
    } else if (this.fields.size() > 65535) {
        throw new IllegalArgumentException("field limit exceeded");
    } else {
        this.cp.getClass(dotToSlash(this.className));
        this.cp.getClass("java/lang/reflect/Proxy");
        var1 = this.interfaces;
        var2 = var1.length;

        for(var3 = 0; var3 < var2; ++var3) {
            var4 = var1[var3];
            this.cp.getClass(dotToSlash(var4.getName()));
        }

        this.cp.setReadOnly();
        ByteArrayOutputStream var13 = new ByteArrayOutputStream();
        DataOutputStream var14 = new DataOutputStream(var13);

        try {
            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);
            Class[] var17 = this.interfaces;
            int var18 = var17.length;

            for(int var19 = 0; var19 < var18; ++var19) {
                Class var22 = var17[var19];
                var14.writeShort(this.cp.getClass(dotToSlash(var22.getName())));
            }

            var14.writeShort(this.fields.size());
            var15 = this.fields.iterator();

            while(var15.hasNext()) {
                ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo)var15.next();
                var20.write(var14);
            }

            var14.writeShort(this.methods.size());
            var15 = this.methods.iterator();

            while(var15.hasNext()) {
                ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo)var15.next();
                var21.write(var14);
            }

            var14.writeShort(0);
            return var13.toByteArray();
        } catch (IOException var9) {
            throw new InternalError("unexpected I/O Exception", var9);
        }
    }
}

这个方法就是将我们的realSubject.request方法转换成h.invoke()方法过程,由于oracle公司并没有开源这部分代码,读起来比较困难,我也理解了一个大概

private ProxyGenerator.MethodInfo generateMethod() throws IOException {
    String var1 = ProxyGenerator.getMethodDescriptor(this.parameterTypes, this.returnType);
    ProxyGenerator.MethodInfo var2 = ProxyGenerator.this.new MethodInfo(this.methodName, var1, 17);
    int[] var3 = new int[this.parameterTypes.length];
    int var4 = 1;

    for(int var5 = 0; var5 < var3.length; ++var5) {
        var3[var5] = var4;
        var4 += ProxyGenerator.getWordsPerType(this.parameterTypes[var5]);
    }

    byte var7 = 0;
    DataOutputStream var9 = new DataOutputStream(var2.code);
    ProxyGenerator.this.code_aload(0, var9);
    var9.writeByte(180);
    var9.writeShort(ProxyGenerator.this.cp.getFieldRef("java/lang/reflect/Proxy", "h", "Ljava/lang/reflect/InvocationHandler;"));
    ProxyGenerator.this.code_aload(0, var9);
    var9.writeByte(178);
    var9.writeShort(ProxyGenerator.this.cp.getFieldRef(ProxyGenerator.dotToSlash(ProxyGenerator.this.className), this.methodFieldName, "Ljava/lang/reflect/Method;"));
    if (this.parameterTypes.length > 0) {
        ProxyGenerator.this.code_ipush(this.parameterTypes.length, var9);
        var9.writeByte(189);
        var9.writeShort(ProxyGenerator.this.cp.getClass("java/lang/Object"));

        for(int var10 = 0; var10 < this.parameterTypes.length; ++var10) {
            var9.writeByte(89);
            ProxyGenerator.this.code_ipush(var10, var9);
            this.codeWrapArgument(this.parameterTypes[var10], var3[var10], var9);
            var9.writeByte(83);
        }
    } else {
        var9.writeByte(1);
    }

    var9.writeByte(185);
    var9.writeShort(ProxyGenerator.this.cp.getInterfaceMethodRef("java/lang/reflect/InvocationHandler", "invoke", "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;"));
    var9.writeByte(4);
    var9.writeByte(0);
    if (this.returnType == Void.TYPE) {
        var9.writeByte(87);
        var9.writeByte(177);
    } else {
        this.codeUnwrapReturnValue(this.returnType, var9);
    }

    short var6;
    short var8 = var6 = (short)var2.code.size();
    List var13 = ProxyGenerator.computeUniqueCatchList(this.exceptionTypes);
    if (var13.size() > 0) {
        Iterator var11 = var13.iterator();

        while(var11.hasNext()) {
            Class var12 = (Class)var11.next();
            var2.exceptionTable.add(new ProxyGenerator.ExceptionTableEntry(var7, var8, var6, ProxyGenerator.this.cp.getClass(ProxyGenerator.dotToSlash(var12.getName()))));
        }

        var9.writeByte(191);
        var6 = (short)var2.code.size();
        var2.exceptionTable.add(new ProxyGenerator.ExceptionTableEntry(var7, var8, var6, ProxyGenerator.this.cp.getClass("java/lang/Throwable")));
        ProxyGenerator.this.code_astore(var4, var9);
        var9.writeByte(187);
        var9.writeShort(ProxyGenerator.this.cp.getClass("java/lang/reflect/UndeclaredThrowableException"));
        var9.writeByte(89);
        ProxyGenerator.this.code_aload(var4, var9);
        var9.writeByte(183);
        var9.writeShort(ProxyGenerator.this.cp.getMethodRef("java/lang/reflect/UndeclaredThrowableException", "<init>", "(Ljava/lang/Throwable;)V"));
        var9.writeByte(191);
    }

    if (var2.code.size() > 65535) {
        throw new IllegalArgumentException("code size limit exceeded");
    } else {
        var2.maxStack = 10;
        var2.maxLocals = (short)(var4 + 1);
        var2.declaredExceptions = new short[this.exceptionTypes.length];

        for(int var14 = 0; var14 < this.exceptionTypes.length; ++var14) {
            var2.declaredExceptions[var14] = ProxyGenerator.this.cp.getClass(ProxyGenerator.dotToSlash(this.exceptionTypes[var14].getName()));
        }

        return var2;
    }
}

总结:

​ 1.首先通过Proxy.newInstance(loader,interface[], handler)进入,然后调用getProxyClass0(loader, intfs)生成Class对象
2. 调用WeakCache对象的get()方法
3. 拿到Loader对应的缓存Map, 生成subkey,判断是否存在缓存,如果有,取出来返回
4. 没有缓存就生成Factory,然后调用ProxyClassFactory的apply方法
5. 调用ProxyGenerator.generateProxyClass()方法
6. 调用ProxyGenerator.generateClassFile()方法
7. 生成构造器
8. 实现代理实现类的具体方法,调用generateMethod()方法
9. 最后调用构造方法生成实例返回

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章