reflect包- Proxy类

带着疑问

  • Proxy 类的作用
  • 怎样使用Proxy 类
  • Proxy 工作原理是什么
  • 产生的Proxy 代理类结构是什么
  • 反推Proxy的用法

Proxy 的作用

Proxy类 提供了静态方法用来创建动态代理类以及其实例,同时它也是通过调用它的方法产生的动态代理类的父类;这里有两点需要说明:1.动态代理类指的是动态代理类对应的Class 实例;2、 动态代理类的父类: 及所有生成的动态代理类都将继承Proxy类并实现指定的接口方法加上toString,equals,hashcode三个方法。

使用Proxy 类

  • 方式一:使用Proxy类提供的静态方法获取代理类对应的Class 实例,通过此实例基于反射获取构造函数创建代理类, 代码如下:
InvocationHandler handler = new MyInvocationHandler(...);
Class proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);
Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class).newInstance(handler);

这里需要注意的是获取构造函数时需要获取参数为InvocationHandler.class类型的形参构造函数。

  • 方法二:一种更加简单的方法,直接获取代理类的实例。
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),new Class[] { Foo.class },handler);

几个概念:

  • dynamic proxy class: 一个代理类代表在运行时实现了指定接口组的类的Class 实例。
  • proxy instance: 代理类实例是指dynamic proxy class的实例。
  • proxy interface: 代理接口指代理类需要实现的接口

每个代理类有一个关联的InvocationHandler 实例(这个实例成员是在Proxy 类声明的:protected InvocationHandler h)。对代理类调用实现了代理接口的方法时,都会派发到 InvocationHandler 的invoke方法,同时传递三个参数: proxy instance(代理实例),Method(正在被调用的方法),方式形参的数组。调用处理程序根据需要处理编码的方法调用,并且它返回的结果将作为代理实例上的方法调用的结果返回。

一个代理类具有以下特点:

  • 如果所有代理接口都是public: 则代理类是public,final,not abstract.
  • 如果任何一个代理接口不是public: 则代理类是no-public,final,not abstract
  • 代理类的名称是 “$Proxy” + 数字编号
  • 代理类继承自 Proxy 类。
  • 如果代理类实现非公共接口,则它将在与该接口相同的包中定义。 否则,代理类的包也未指定。 请注意,程序包密封不会阻止在运行时在特定程序包中成功定义代理类,也不会由同一个类加载器和具有特定签名者的相同程序包定义类
  • Proxy.isProxyClass:用来检测当前类是否是代理类
  • 每个代理类都有一个公共构造函数,它接受一个参数(接口InvocationHandler的实现)来设置代理实例的调用处理程序。 不必使用反射API来访问公共构造函数,也可以通过调用Proxy.newProxyInstance方法来创建代理实例,该方法将调用Proxy.getProxyClass的操作与使用调用处理程序调用构造函数相结合。

深入Proxy类的原理

要理解Proxy可以从三个重要属性,两个重要内部类

三个重要属性如下:

  • 规定代理类的构造函数的参数类型
 private static final Class[] constructorParams =
        { InvocationHandler.class };
  • 保存代理类的缓存数据结构:
private static final WeakCache[], Class>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

这里需要先弄懂WeakCache的原理与作用

  • 代理实例的InvocationHandler 实例
   protected InvocationHandler h;

两个重要方法如下:

  • 静态方法:newProxyInstance直接获取代理对象实例:
  public static Object newProxyInstance(ClassLoader loader,
                                          Class[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        // 判断Invocation 对象不能为空
        Objects.requireNonNull(h);
        // 复制代理接口
        final Class[] intfs = interfaces.clone();
        // 权限校验主要检查loader是否能够加载代理接口对应的Class 实例
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * 查找代理类的Class 实例
         */
        Class cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
            // 通过反射获取代理类的构造函数
            final Constructor cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            // 调用构造函数并返回代理实例
            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);
        }
    }
  • 看下私有的: getProxyClass0方法
 private static Class getProxyClass0(ClassLoader loader,
                                           Class... interfaces) {
        // 判断接口长度
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }

        // 从缓存中去,没有的话通过ProxyClassFactory 生成,这里要明白WeakCache的机制
        return proxyClassCache.get(loader, interfaces);
    }

两个重要内部类:

  • KeyFactory: 作为参数传递给WeakCache类作为SubFactoryKey函数生成WeakCache需要的subKey, 它很简单,只是放回接口实例对应的hashCode
private static final class KeyFactory
        implements BiFunction[], Object>
    {
        @Override
        public Object apply(ClassLoader classLoader, Class[] interfaces) {
            switch (interfaces.length) {
                case 1: return new Key1(interfaces[0]); // the most frequent
                case 2: return new Key2(interfaces[0], interfaces[1]);
                case 0: return key0;
                default: return new KeyX(interfaces);
            }
        }
    }
  • ProxyClassFactory: 这个才是生成代理类的主角,它有WeakCache内部调用apply方法来触发生成代理类的逻辑,本质上生成代理类就是修改字节码。
private static final class ProxyClassFactory
        implements BiFunction[], Class>
    {
        // 定义代理类的名称前缀
        private static final String proxyClassNamePrefix = "$Proxy";

        // 全局的代理类生成序列数字,它和名称前缀一起构成代理类的名称
        private static final AtomicLong nextUniqueNumber = new AtomicLong();

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

            Map, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            for (Class intf : interfaces) {
                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");
                }
               // 验证代理接收是一个接口类型
                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());
                }
            }

            String proxyPkg = null;     // package to define proxy class in
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
             // 记录非public 代理接口所在包,用来保证生成的代理类在同一个包类,同时也验证所有非public 代理在同一个包
            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) {
                // if no non-public proxy interfaces, use com.sun.proxy package
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }
            // 组装代理类名称
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            /*
             * 生成特殊的代理类,这里也提供了把二进制写成.class文件查看代理类的接口的思路
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
                // 根据代理类的二级制数据调用defineClass0这个native方法由虚拟机生成代理类的Class实例
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                throw new IllegalArgumentException(e.toString());
            }
        }
    }

总体流程如下:
reflect包- Proxy类_第1张图片

查看生成代理类接口

描述的再多不如真实看一下:查看代理类方法参加:https://blog.csdn.net/u011244682/article/details/96335660
代理接口如下:

public interface PersonService {

    public boolean saveUser(String user);

    public String getUserName();
}

由JDK生成的动态代理类如下:

package com.leran;

import com.learn.proxy.PersonService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class proxy01 extends Proxy implements PersonService {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m4;
    private static Method m0;

    public proxy01(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 boolean saveUser(String var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m3, 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 String getUserName() throws  {
        try {
            return (String)super.h.invoke(this, m4, (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"));
            m3 = Class.forName("com.learn.proxy.PersonService").getMethod("saveUser", Class.forName("java.lang.String"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m4 = Class.forName("com.learn.proxy.PersonService").getMethod("getUserName");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

反推代理类的用法

通过查看生成的代理类结构就知道为什么需要传递InvocationHandler 对象已经为什么需要重写invoke方法以及AOP 在对invoke方法的处理作用。

相关文件

WeakCache的使用分析:https://blog.csdn.net/u011244682/article/details/96428467
Class类的作用:https://blog.csdn.net/u011244682/article/details/95996222

你可能感兴趣的:(JAVA基础)