zoukankan      html  css  js  c++  java
  • 动态代理源码解析

    接口:
    public interface Person {
        String getString();
    }
    实现类:
    public class Student implements Person{
        public String getString(){
            return "sss";
        }
    }
     
    InvocationHandler实现类:
    public class StudentInvocationHandler<T> implements InvocationHandler {
        T target;
        public StudentInvocationHandler(T target) {
            this.target = target;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            return method.invoke(target,args);
        }
    }

    测试类:
    public class Test {
        public static void main(String[] args) {
            Student student=new Student();
            StudentInvocationHandler handler = new StudentInvocationHandler<Person>(student);
            //生成动态代理
            Person person =(Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, handler);
            System.out.println(person.getString());
        }
    }
     
    生成的代理类在debug模式下如下,可以看到person值为代理类$Proxy0,是Student的代理类,此类的特点是和Student一样都实现了Person接口。
     

    可以通过以下方式获取$Proxy0的源码:
    public static void main(String[] args)throws Exception{
            byte[] proxyClass=ProxyGenerator.generateProxyClass("$Proxy0",Student.class.getInterfaces());
            //将代理类person的源码输出到文件,然后用IDEA等工具打开查看
            File file=new File("E:/$Proxy0.class");
            FileOutputStream fileOutputStream=new FileOutputStream(file);
            fileOutputStream.write(proxyClass);
            fileOutputStream.close();
        }

     代理类的结构如下:


    $Proxy0的源码如下,可见代理类实现了Person接口并且继承了Proxy类,当执行代理类的getString方法时,就会执行StudentInvocationHandler的invoke方法
    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //
    import DynamicProxy.Person;
    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 Person {
        private static Method m1;
        private static Method m2;
        private static Method m0;
        private static Method m3;
        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});
            } 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 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);
            }
        }
        public final String getString() throws  {
            try {
                return (String)super.h.invoke(this, m3, (Object[])null);//会调用父类(Proxy类)的h(StudentInvocationHandler)的invoike方法
            } 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");
                m0 = Class.forName("java.lang.Object").getMethod("hashCode");
                m3 = Class.forName("DynamicProxy.Person").getMethod("getString");
            } catch (NoSuchMethodException var2) {
                throw new NoSuchMethodError(var2.getMessage());
            } catch (ClassNotFoundException var3) {
                throw new NoClassDefFoundError(var3.getMessage());
            }
        }
    }
    源码解析:Proxy.newProxyInstance
    此方法为指定接口返回代理类的一个实例
    public class Proxy implements java.io.Serializable {
        private static final long serialVersionUID = -2222568056686623797L;
        /** parameter types of a proxy class constructor */
        private static final Class<?>[] constructorParams =
            { InvocationHandler.class };
         /**
         * the invocation handler for this proxy instance.
         * @serial
         */
        protected InvocationHandler h;   
    
     /**
         * Returns an instance of a proxy class for the specified interfaces
         * that dispatches method invocations to the specified invocation
         * handler.
         *
         * <p>{@code Proxy.newProxyInstance} throws
         * {@code IllegalArgumentException} for the same reasons that
         * {@code Proxy.getProxyClass} does.
         *
         * @param   loader the class loader to define the proxy class
         * @param   interfaces the list of interfaces for the proxy class
         *          to implement
         * @param   h the invocation handler to dispatch method invocations to
         * @return  a proxy instance with the specified invocation handler of a
         *          proxy class that is defined by the specified class loader
         *          and that implements the specified interfaces
         * @throws  IllegalArgumentException if any of the restrictions on the
         *          parameters that may be passed to {@code getProxyClass}
         *          are violated
         * @throws  SecurityException if a security manager, <em>s</em>, is present
         *          and any of the following conditions is met:
         *          <ul>
         *          <li> the given {@code loader} is {@code null} and
         *               the caller's class loader is not {@code null} and the
         *               invocation of {@link SecurityManager#checkPermission
         *               s.checkPermission} with
         *               {@code RuntimePermission("getClassLoader")} permission
         *               denies access;</li>
         *          <li> for each proxy interface, {@code intf},
         *               the caller's class loader is not the same as or an
         *               ancestor of the class loader for {@code intf} and
         *               invocation of {@link SecurityManager#checkPackageAccess
         *               s.checkPackageAccess()} denies access to {@code intf};</li>
         *          <li> any of the given proxy interfaces is non-public and the
         *               caller class is not in the same {@linkplain Package runtime package}
         *               as the non-public interface and the invocation of
         *               {@link SecurityManager#checkPermission s.checkPermission} with
         *               {@code ReflectPermission("newProxyInPackage.{package name}")}
         *               permission denies access.</li>
         *          </ul>
         * @throws  NullPointerException if the {@code interfaces} array
         *          argument or any of its elements are {@code null}, or
         *          if the invocation handler, {@code h}, is
         *          {@code null}
         */
        @CallerSensitive
        public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
            throws IllegalArgumentException
        {
            Objects.requireNonNull(h);
            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)
             */
            Class<?> cl = getProxyClass0(loader, intfs);
            /*
             * Invoke its constructor with the designated invocation handler.
             */
            try {
                if (sm != null) {
                    checkNewProxyPermission(Reflection.getCallerClass(), cl);
                }
             //根据构造器参数类型获取Constructor<?>类,此测试中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;
                        }
                    });
                }
                //根据构造器和构造器参数生成代理类实例,此测试中h的值为
                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);
            }
        }
    }
     
     
  • 相关阅读:
    如何解决flash跑到层上面的问题?How to resolve the div layer appear over the top of flash?
    WSDL
    Java 实现解压缩文件
    Eclipse 插件TFS 注册码
    JNLP
    SOAP
    检测客户端是否安装了JWS Java Web Start
    Java打包JRE于exe中方法
    Java解压文件代码(相当于你在目录中选中压缩文件 右键解压)
    Java代码实现利用google实现多语言翻译案例
  • 原文地址:https://www.cnblogs.com/BonnieWss/p/11653806.html
Copyright © 2011-2022 走看看