JDK 动态代理执行流程解析

被代理类接口:

package reflect;

interface TestInterface{
    void print();
}

被代理类实现:

package reflect;

class Test implements TestInterface{
    public void print() {
        System.out.println("I am print");
    }
}

InvocationHandler实现类,执行特定被代理类方法的额外操作

class TestProxy implements InvocationHandler {
    private Object test;

    // 生成代理类
    public Object createInstance(Object test) {
        this.test = test;
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), test.getClass().getInterfaces(), this);
    }

    // InvocationHandler的invoke方法的具体实现
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before");

        // 调用被代理类的方法。
        // method是指定调用的被代理类的方法,该方法可以是接口类的方法,也可以是被代理类的方法
        // this.test是被代理类的实例
        Object obj = method.invoke(this.test, args);

        System.out.println("after");
        return obj;
    }
}

测试用例:

public class ProxyTest {
    public static void main(String[] args) {
        TestProxy testProxy = new TestProxy();
        TestInterface test = (TestInterface) testProxy.createInstance(new Test());
        test.print();
    }
}

jdk动态代理得核心是:
InvocationHandler的实现类TestProxy中调用Proxy.newProxyInstance生成代理类字节码、使用被代理类的类加载器加载代理类字节码、生成代理类实例

下面是生成的代理类字节码
(在java命令中增加-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true参数可将字节码保存到磁盘上)

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package general;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

final class $Proxy0 extends Proxy implements TestInterface {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    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 print() throws  {
        try {
            super.h.invoke(this, m3, (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 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")});
            m3 = Class.forName("general.TestInterface").getMethod("print", new Class[0]);
            m2 = Class.forName("java.lang.Object").getMethod("toString", 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());
        }
    }
}

可以看到,生成的代理类继承了java.lang.reflect.Proxy以及实现了被代理类的TestInterface接口。

结合测试用例来看:

public class ProxyTest {
    public static void main(String[] args) {
        TestProxy testProxy = new TestProxy();
        TestInterface test = (TestInterface) testProxy.createInstance(new Test());
        test.print();
    }
}

第一行

TestProxy testProxy = new TestProxy();

创建InvocationHandler的实例

第二行

TestInterface test = (TestInterface) testProxy.createInstance(new Test());

InvocationHandler生成代理类对象实例,并赋值给被代理类的接口TestInterface(多态,向上转型)

第三行

test.print();

调用代理类的print方法:

public final void print() throws  {
   try {
       super.h.invoke(this, m3, (Object[])null);
   } catch (RuntimeException | Error var2) {
       throw var2;
   } catch (Throwable var3) {
       throw new UndeclaredThrowableException(var3);
   }
}

在代理类的print方法中,回调了InvocationHandler实现类TestProxy的invoke方法。这里m3是被代理类中的print方法的Method实例,在代理类的静态代码块中初始化(类加载阶段初始化):

static {
   try {
       m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
       m3 = Class.forName("general.TestInterface").getMethod("print", new Class[0]);
       m2 = Class.forName("java.lang.Object").getMethod("toString", 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());
   }
}

在TestProxy类的invoke方法中,通过

Object obj = method.invoke(this.test, args);

这一行通过反射调用被代理类的print方法,在这一行断点可以看到如下信息
这里写图片描述
这就是jdk动态代理的执行流程。

拓展:

  • jdk动态代理之所以只能代理接口是因为代理类本身已经extends了Proxy,而java是不允许多重继承的,但是允许实现多个接口
  • 另一种将代理类字节码写入磁盘的方式如下(直接调用代理类字节码生成接口,并写入磁盘上,这和之前介绍的方式是一样的原理):
public static void writeProxyClassToHardDisk(String path) {
    // 获取代理类的字节码  
    byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", UserServiceImpl.class.getInterfaces());  

    FileOutputStream out = null;  

    try {  
        out = new FileOutputStream(path);  
        out.write(classFile);  
        out.flush();  
    } catch (Exception e) {  
        e.printStackTrace();  
    } finally {  
        try {  
            out.close();  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    }  
}  

参考文档:
http://rejoy.iteye.com/blog/1627405

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值