jdk代理

作者: 北海北_6dc3 | 来源:发表于2020-04-09 20:34 被阅读0次

    使用示例

    • 定义接口
    public interface Subject {
        void doSomething();
    }
    
    • 定义实现
    public class RealSubject implements Subject {
        @Override
        public void doSomething() {
            System.out.println("RealSubject do something");
        }
    }
    
    • 定义jdk代理
    public class JDKDynamicProxy implements InvocationHandler {
    
        private Object target;
    
        public JDKDynamicProxy(Object target) {
            this.target = target;
        }
    
        /**
         * 获取被代理接口实例对象
         * @param <T>
         * @return
         */
        public <T> T getProxy() {
            return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("Do something before");
            Object result = method.invoke(target, args);
            System.out.println("Do something after");
            return result;
        }
    }
    
    • 调用
    public class Client {
        public static void main(String[] args) {
            // 保存生成的代理类的字节码文件
            System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
    
            // jdk动态代理测试
            Subject subject = new JDKDynamicProxy(new RealSubject()).getProxy();
            subject.doSomething();
        }
    }
    

    我们看到如果使用jdk代理,需要的核心要素有哪些?
    1、接口及实现目标类
    2、JDK代理类需要实现一个InvocationHandler 接口invoke方法。

    这个实现,我们可以看出,是代理了类中所有方法。实现了相同的操作;
    那么它的内部实现原理是什么?

    原理

    • 生成代理对象
    //核心实现,生成代理对象。
    Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    
    public class Proxy implements java.io.Serializable {
      public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
            throws IllegalArgumentException
        {
            final Class<?>[] intfs = interfaces.clone();
    、
            /*
             * 核心生成代理类
             */
            Class<?> cl = getProxyClass0(loader, intfs);
    
            /*
             *通过handler生成实例
             */
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            return cons.newInstance(new Object[]{h});
        }
     }
    
    • 核心生成代理类,我们可以看到核心只需要相应接口和loader。
        private static Class<?> getProxyClass0(ClassLoader loader,
                                               Class<?>... interfaces) {
            return proxyClassCache.get(loader, interfaces);
        }
    
        // proxyClassCache.get
        public V get(K key, P parameter) {
            Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
            Factory factory = new Factory(key, parameter, subKey, valuesMap);
            return factory.get();
        }
    
            // factory.get
            public synchronized V get() {
                 valueFactory.apply(key, parameter)
            }
    //其中,valueFactory是构造函数中构造的。
    public class Proxy {
        private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
            proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
    }
    
    final class WeakCache<K, P, V> {
        public WeakCache(BiFunction<K, P, ?> subKeyFactory,
                         BiFunction<K, P, V> valueFactory) {
            this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
            this.valueFactory = Objects.requireNonNull(valueFactory);
        }
    }
    //所以valueFactory就是ProxyClassFactory
    //继续查看applay方法
    
            // 所有代理类名称前缀为$Proxy
            private static final String proxyClassNamePrefix = "$Proxy";
            // 全局自增编号,和proxyClassNamePrefix 进行拼接,组成代理类名
            private static final AtomicLong nextUniqueNumber = new AtomicLong();
            public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
                //接口校验....
                String proxyPkg = null;     // package to define proxy class in
                int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
    
                /*
                 * 非public接口,代理类的包名与接口的包名相同
                 */
                for (Class<?> intf : interfaces) {
                     ..
                }
    
                if (proxyPkg == null) {
                    // if no non-public proxy interfaces, use com.sun.proxy package
                    proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
                }
                /*
                 *生成代理类名
                 */
                long num = nextUniqueNumber.getAndIncrement();
                String proxyName = proxyPkg + proxyClassNamePrefix + num;
                /*
                 * 生成代理类字节码。核心!!!!!
                 */
                byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                    proxyName, interfaces, accessFlags);
            }
    
    • 代理类字节码生成。这个是核心类。
      这个类的命名空间package sun.misc,是个jdk提供的功能类
    public class ProxyGenerator {
        public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
            ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
            final byte[] var4 = var3.generateClassFile();
      // 是否要将生成代理类的字节码文件保存到磁盘中
            if (saveGeneratedFiles) {
                // ....
            }
        }
    
        //new ProxyGenerator(var0, var1, var2);
        private ProxyGenerator(String var1, Class<?>[] var2, int var3) {
            this.className = var1;
            this.interfaces = var2;
            this.accessFlags = var3;
        }
       //var3.generateClassFile();核心中的核心。
        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();
            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());
            } 
        }
    
       //generateClassFile中的三个添加方法
        private static Method hashCodeMethod;
        private static Method equalsMethod;
        private static Method toStringMethod;
        static {
            try {
                hashCodeMethod = Object.class.getMethod("hashCode", new Class[0]);
                equalsMethod = Object.class.getMethod("equals", new Class[]{Object.class});
                toStringMethod = Object.class.getMethod("toString", new Class[0]);
            } catch (NoSuchMethodException var1) {
                throw new NoSuchMethodError(var1.getMessage());
            }
        }
    
    
            private ProxyGenerator.MethodInfo generateMethod() throws IOException {
                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);
               // ...字节流写入操作
            }
    
    }
    
    • 生成的代理类
      在测试案例中,设置系统属性sun.misc.ProxyGenerator.saveGeneratedFiles值为true
     // 保存生成的代理类的字节码文件
     System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
    

    判定是否保存

    public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
            ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
            final byte[] var4 = var3.generateClassFile();
            // 是否要将生成代理类的字节码文件保存到磁盘中
            if (saveGeneratedFiles) {
                // ....
            }
            return var4;
        }
    

    打开$Proxy0.class文件如下:

    package com.sun.proxy;
    
    import com.example.aop.jdk.Subject;
    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 Subject {
        private static Method m1;
        private static Method m4;
        private static Method m2;
        private static Method m3;
        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})).booleanValue();
            } catch (RuntimeException | Error var3) {
                throw var3;
            } catch (Throwable var4) {
                throw new UndeclaredThrowableException(var4);
            }
        }
    
        public final void doSomething() throws  {
            try {
                super.h.invoke(this, m4, (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 void doSomething1() 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)).intValue();
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        static {
            try {
                m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
                m4 = Class.forName("com.example.aop.jdk.Subject").getMethod("doSomething", new Class[0]);
                m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
                m3 = Class.forName("com.example.aop.jdk.Subject").getMethod("doSomething1", new Class[0]);
                m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
            } catch (NoSuchMethodException var2) {
                throw new NoSuchMethodError(var2.getMessage());
            } catch (ClassNotFoundException var3) {
                throw new NoClassDefFoundError(var3.getMessage());
            }
        }
    }
    
    

    1、继承了Proxy类,实现了代理的接口,由于java不能多继承,这里已经继承了Proxy类了,不能再继承其他的类,所以JDK的动态代理不支持对实现类的代理,只支持接口的代理。
    2、提供了一个使用InvocationHandler作为参数的构造方法,最终所有方法都是调用此方法。并把真实对象方法传递进来,通过反射调用。
    参考资料:
    JDK动态代理实现原理

    相关文章

      网友评论

          本文标题:jdk代理

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