zoukankan      html  css  js  c++  java
  • Java反射(五)动态代理底层实现

    在前文Java反射(三)反射与代理设计模式 中描述了动态代理的使用方法,本文主要记录Java动态代理的实现原理。

    大致思路:(1)用户通过Proxy.newProxyInstance方法,传入ClassLoader、接口数组、和InvocationHandler实现类(包含具体被代理对象和对其具体处理逻辑);

    (2)底层根据接口数组和InvocationHandler在运行时生成代理类字节码,即代理类实现接口数组,同时组合InvocationHandler,对被代理类添加额外功能;

    (3)然后通过传入的ClassLoader进行加载,再实例化后返回,即得到代理对象。

    1.代理核心类

    (1) ProxyClassFactory类

    代理类创建工厂类ProxyClassFactory,作为Proxy嵌套类,根据ClassLoader和接口数组定义代理Class,核心代码如下:

    /**
         * 代理Class工厂,可以根据ClassLoader和接口数组定义代理Class(A factory function that generates, defines and returns the proxy class given
         * the ClassLoader and array of interfaces.)
         */
        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();
    
            //具体生成代理class方法
            @Override
            public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
    
                //接口校验等处理
    
                //方法访问修饰符,public和final
                int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
                
                //构建代理类名称
                String proxyName = proxyPkg + proxyClassNamePrefix + num;
    
                //生成代理类字节码(Generate the specified proxy class.)
                byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                    proxyName, interfaces, accessFlags);
                try {
                    //根据传入的ClassLoader加载代理类
                    return defineClass0(loader, proxyName,
                                        proxyClassFile, 0, proxyClassFile.length);
                } catch (ClassFormatError e) {
                    
                }
            }
        }

     其中 byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);,通过ProxyGenerator类生成的字节数组即为代理类字节码,然后通过传入的ClassLoader进行加载。

    (2)Proxy类

    静态方法newProxyInstance,是代理类实现的入口,开发者传入ClassLoader、被代理的接口和自定义的InvocationHandler。

    public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
            throws IllegalArgumentException
        {
    
            //(1)查找或生成代理类
            Class<?> cl = getProxyClass0(loader, intfs);
    
            //调用代理类构造器,并注入invocation handler.
            try {
                //获取代理类的构造函数,如果是非Public,修改访问权限
                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;
                        }
                    });
                }
                //(2)实例化代理类,将InvocationHandler作为参数注入代理类
                return cons.newInstance(new Object[]{h});
            } catch (IllegalAccessException|InstantiationException e) {
            } catch (InvocationTargetException e) {
            } catch (NoSuchMethodException e) {
            }
        }

      (1)getProxyClass0方法是查找或生成代理类的方法,它是在缓存中查找是否存在代理类,如果不存在则通过调代理工厂类生成。

    /**
         * a cache of proxy classes
         */
     private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
            proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
    
     private static Class<?> getProxyClass0(ClassLoader loader,
                                               Class<?>... interfaces) {
            //接口数量不能大于65535
            if (interfaces.length > 65535) {
                throw new IllegalArgumentException("interface limit exceeded");
            }
            //如果缓存中存在,则直接返回;否则通过ProxyClassFactory工厂创建
            return proxyClassCache.get(loader, interfaces);
        }

     (2)cons.newInstance(new Object[]{h}),创建代理类实例,将InvocationHandler注入代理类中。Proxy类通过组合方式包含InvocationHandler类,代理类在实现传入接口的同时,还会继承Proxy(后文可见)。

    /**
         * the invocation handler for this proxy instance.
         * @serial
         */
        protected InvocationHandler h;
    
    /**
         * Constructs a new {@code Proxy} instance from a subclass
         * (typically, a dynamic proxy class) with the specified value
         * for its invocation handler.
         *
         * @param  h the invocation handler for this proxy instance
         *
         * @throws NullPointerException if the given invocation handler, {@code h},
         *         is {@code null}.
         */
        protected Proxy(InvocationHandler h) {
            Objects.requireNonNull(h);
            this.h = h;
        }

    2.代理类结构

    (1)定义被代理的接口和实现类,存在2个方法

    interface Msg{
        void send(String msg, int seq);
        String recv(String msg);
    }
    
    class MsgImpl implements Msg{
    
        public void send(String msg,int seq) {
            System.out.println("消息发送:"+msg);
            System.out.println("消息序号:"+seq);
        }
    
        public String recv(String msg) {
            System.out.println("消息接收:"+msg);
            return msg;
        }
    }

      (2)将ProxyClassFactory工厂类中关键代码抽出,获取代理类字节码

    public class ReflectFile {
        public static void main(String[]args) throws Exception{
            //方法修饰符 public和final
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
            //代理类名称
            String proxyName = "MsgImplProxy";
            //ProxyGenerator类生成代理类字节码
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                    proxyName, MsgImpl.class.getInterfaces(), accessFlags);
            //输出到class文件中
            FileOutputStream out = new FileOutputStream(new File(proxyName+".class"));
            out.write(proxyClassFile);
            out.close();
        }
    }

     (3)反编译代理类,详细信息见注解

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.lang.reflect.UndeclaredThrowableException;
    import test.Msg;
    /**
    *代理类MsgImplProxy继承自Proxy(包含InvocationHandler,处理代理逻辑),并实现Msg(代理三要素中的接口)
    */
    public final class MsgImplProxy extends Proxy implements Msg {
        //包含5个方法,其中m0、m1、m2为Object方法hashCode、equals、toString;m3 和 m4是被代理接口的方法
        //方法初始化放在static中,在类加载时进行初始化
        private static Method m1;
        private static Method m2;
        private static Method m4;
        private static Method m3;
        private static Method m0;
        
        static {
            try {
                m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
                m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
                m4 = Class.forName("test.Msg").getMethod("send", new Class[]{Class.forName("java.lang.String"), Integer.TYPE});
                m3 = Class.forName("test.Msg").getMethod("recv", new Class[]{Class.forName("java.lang.String")});
                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());
            }
        }
    
        //代理类构造函数,参数为InvocationHandler,调用父类Proxy的构造,将InvocationHandler设置到变量中
        public MsgImplProxy(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 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);
            }
        }
    
        //被代理接口方法send
        public final void send(String var1, int var2) throws  {
            try {
                //调用InvocationHandler的invoke方法,传入代理对象、被代理方法实例、被代理方法参数
                super.h.invoke(this, m4, new Object[]{var1, Integer.valueOf(var2)});
            } catch (RuntimeException | Error var4) {
                throw var4;
            } catch (Throwable var5) {
                throw new UndeclaredThrowableException(var5);
            }
        }
        //被代理接口方法recv
        public final String recv(String var1) throws  {
            try {
                return (String)super.h.invoke(this, m3, new Object[]{var1});
            } catch (RuntimeException | Error var3) {
                throw var3;
            } catch (Throwable var4) {
                throw new UndeclaredThrowableException(var4);
            }
        }
    
        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);
            }
        }
    }

     综上:

    (1)Proxy创建的代理类MsgImplProxy继承Proxy,同时还实现被代理类接口,与静态代理相似 。

    (2)代理类执行方法调用时,会调InvocationHandler的invoke方法,该方法是开发者自定义功能的地方。

    (3)在构造InvocationHandler时,需要将被代理类对象传入(因为需要执行 method.invoke(被代理对象,方法参数)),从而实现被代理对象的代理和附加额外的功能。

    (4)下篇文章将采用注解、反射、动态代理、工厂模式进行实践。

  • 相关阅读:
    传统线程互斥和同步通信
    【计算机视觉】人脸表情识别技术
    【计算机视觉】人脸识别--人脸识别技术综述
    【计算机视觉】人脸识别--人脸识别技术综述
    【计算机视觉】人脸识别之人脸对齐(一)--定义及作用
    【计算机视觉】人脸识别之人脸对齐(一)--定义及作用
    【神经网络与深度学习】转-caffe安装吐血总结
    【神经网络与深度学习】转-caffe安装吐血总结
    【图像处理与医学图像处理】YUV与RGB格式转换速度几种方法对比
    【图像处理与医学图像处理】YUV与RGB格式转换速度几种方法对比
  • 原文地址:https://www.cnblogs.com/shuimuzhushui/p/12681947.html
Copyright © 2011-2022 走看看