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)下篇文章将采用注解、反射、动态代理、工厂模式进行实践。

posted @ 2020-04-12 16:07  水木竹水  阅读(670)  评论(0编辑  收藏  举报