美文网首页log4j
JDK Proxy动态代理解析

JDK Proxy动态代理解析

作者: 晴天哥_王志 | 来源:发表于2022-01-29 14:53 被阅读0次

    开篇

    • 日常阅读开源的代码框架的时候经常会到Proxy动态代理的应用场景,抽空研究一下。
    • 借助于Proxy的demo和反编译动态代理代码来分析调用过程。
    • 借助于Proxy的动态代理类的源码分析下动态类的生成过程。

    Proxy应用场景

    package com.sunboy;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import sun.misc.ProxyGenerator;
    
    public class ViewProxyClass {
    
        public static void main(String[] args) throws Exception {
    
            Game gamePlayer = new GamePalyer("张三");
    
            ClassLoader classLoader = gamePlayer.getClass().getClassLoader();
            Class<?>[] interfaces = gamePlayer.getClass().getInterfaces();
            // 生成动态代理的基本操作
            Game proxy = (Game) Proxy.newProxyInstance(classLoader, interfaces, new GameInvocation(gamePlayer));
            proxy.paly();
    
            // 生成动态代理的源码的调试方法
            byte[] bts = ProxyGenerator.generateProxyClass("$GameProxy", interfaces);
            FileOutputStream fos = new FileOutputStream(new File("D:/tmp/$GameProxy.class"));
            fos.write(bts);
            fos.flush();
            fos.close();
        }
    
        // 接口的定义
        interface Game {
            public void paly();
        }
    
        // 接口的实现
        static class GamePalyer implements Game {
    
            private String name;
    
            public GamePalyer(String name) {
                this.name = name;
            }
    
            @Override
            public void paly() {
                System.out.println(this.name + " playing ...");
            }
        }
    
        // 动态代理的封装对象
        static class GameInvocation implements InvocationHandler {
    
            private Game target;
    
            public GameInvocation(Game target) {
                this.target = target;
            }
    
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println(target + "被代理");
                method.invoke(this.target, args);
                return proxy;
            }
        }
    }
    
    • Proxy动态代理类基于Interface维度的,被代理类需要实现Interface,如案例中提到的GamePalyer类实现Game接口。
    • Proxy的动态代理封装类需要实现InvocationHandler接口,如案例中的GameInvocation对象。
    • 动态代理类的生成通过Proxy.newProxyInstance来实现。动态代理类的代码是由Proxy的接口动态定义生成,可以通过ProxyGenerator.generateProxyClass("$GameProxy", interfaces)生成代理类并保存到class文件后反编译后观察。
    • InvocationHandler的第一个参数Object是指动态生成的代理类,第二个参数是被代理的方法,第三方参数是动态入参。

    Proxy动态代理类

    import com.sunboy.ViewProxyClass.Game;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.lang.reflect.UndeclaredThrowableException;
    
    public final class $GameProxy extends Proxy implements Game {
        private static Method m1;
        private static Method m2;
        private static Method m3;
        private static Method m0;
    
        public $GameProxy(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 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 void paly() throws  {
            try {
                super.h.invoke(this, m3, (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"));
                m2 = Class.forName("java.lang.Object").getMethod("toString");
                m3 = Class.forName("com.sunboy.ViewProxyClass$Game").getMethod("paly");
                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 class Proxy implements java.io.Serializable {
    
        private static final long serialVersionUID = -2222568056686623797L;
        protected InvocationHandler h;
    
         protected Proxy(InvocationHandler h) {
            Objects.requireNonNull(h);
            this.h = h;
        }
    }
    
    • 动态代理类GameProxy继承Proxy并implement被代理接口(如案例中的Game)。
    • 动态代理类GameProxy的构造函数$GameProxy(InvocationHandler var1)的参数为InvocationHandler 对象,并传给父类Proxy。
    • 动态代理类GameProxy通过Class.forName来加载被代理接口,并通过getMethod获取被代理的Method。
    • 动态代理类重写了被代理的Method,并通过 super.h.invoke()调用InvocationHandler的invoke方法。
    • 动态代理类核心就是重载被代理的方法,并在重载的方法内部调用代理对象Invocation的invoke方法。代理的实现代码在Invocation里面

    动态代理类工厂

    public class Proxy implements java.io.Serializable {
    
        private static final class ProxyClassFactory
            implements BiFunction<ClassLoader, Class<?>[], Class<?>>
        {
            private static final String proxyClassNamePrefix = "$Proxy";
    
            private static final AtomicLong nextUniqueNumber = new AtomicLong();
    
            @Override
            public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
                // 检查被代理的Interface的合法性
                Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
                for (Class<?> intf : interfaces) {
                    Class<?> interfaceClass = null;
                    try {
                        interfaceClass = Class.forName(intf.getName(), false, loader);
                    } catch (ClassNotFoundException e) {
                    }
                    if (interfaceClass != intf) {
                        throw new IllegalArgumentException(
                            intf + " is not visible from class loader");
                    }
    
                    if (!interfaceClass.isInterface()) {
                        throw new IllegalArgumentException(
                            interfaceClass.getName() + " is not an interface");
                    }
    
                    if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                        throw new IllegalArgumentException(
                            "repeated interface: " + interfaceClass.getName());
                    }
                }
    
                // 检查package的合法性
                String proxyPkg = null;     // package to define proxy class in
                int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
    
                for (Class<?> intf : interfaces) {
                    int flags = intf.getModifiers();
                    if (!Modifier.isPublic(flags)) {
                        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");
                        }
                    }
                }
    
                if (proxyPkg == null) {
                    proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
                }
    
                long num = nextUniqueNumber.getAndIncrement();
                String proxyName = proxyPkg + proxyClassNamePrefix + num;
                // 1、生成动态代理的类
                byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                    proxyName, interfaces, accessFlags);
    
                try {
                    // 2、加载动态代理的类
                    return defineClass0(loader, proxyName,
                                        proxyClassFile, 0, proxyClassFile.length);
                } catch (ClassFormatError e) {
    
                    throw new IllegalArgumentException(e.toString());
                }
            }
        }
    }
    
    • ProxyGenerator.generateProxyClass()负责生成动态代理类。
    • defineClass0负责加载新生成的动态代理类并返回。
    • ProxyClassFactory负责动态生成代理类的工厂。

    相关文章

      网友评论

        本文标题:JDK Proxy动态代理解析

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