Java:Jdk动态代理技术解析

当前版本jdk1.8

1. 声明

当前内容主要为解析jdk的动态代理技术,当前内容参考jdk源码

2. 创建jdk方式解析

基本的jdk动态代理创建方法如下:

public static Object newProxyInstance(
ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)

一般是需要被代理的接口和自定义的InvocationHandler,找到如下方法内容

在这里插入图片描述
从注释中可以得到信息,代理类是被生成出来的,然后动态加载到jvm中的,最后通过实例化操作返回给用户的

继续查看生成代理类的方法
在这里插入图片描述
其中限定了jdk代理的接口必须小于65535个,且注释中表明是通过加载器方式且使用了缓存,但是实际创建代理类是使用ProxyClassFactory生成的

此时直接找到ProxyClassFactory这个类并找到其中的方法

在这里插入图片描述
可以发现实际上为ProxyGenerator方式生成的代理,此时继续找到ProxyGenerator类,并得到如下内容
在这里插入图片描述
这个是一个class文件的基本构造,且该class文件是生成的byte[],并且发现了如下特点

  1. 该代理类的超类就是Proxy
  2. 该代理类实际上本身就是实现了接口的类

3. 手动将查看生成的代理类的byte[]并解析

这里可以将ProxyGenerator的源码得到并实现byte[]生成且写出到文件中,这里使用一个简单的代理Demo

public interface Say {
		void say();
	}

public static class Me implements Say {
	public void say() {
		System.out.println("say .........");
	}
}

public static void main(String[] args) throws FileNotFoundException {
		int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
		Class<?>[] interfaces = { Say.class };
		String proxyName = "com.hy.java.proxy.HY$Proxy";
		byte[] generateProxyClass = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);

		String outputPath = "C:\\Users\\admin\\Desktop\\a.class";
		try (FileOutputStream fileOutputStream = new FileOutputStream(new File(outputPath))) {
			fileOutputStream.write(generateProxyClass, 0, generateProxyClass.length);
		} catch (IOException e) { // TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

执行后并得到生成的文件a.class,接下来开始分析实际的字节码
执行命令:javap -verbose a.class
在这里插入图片描述

public final class com.hy.java.proxy.HY$Proxy extends java.lang.reflect.Proxy implements com.hy.java.proxy.factory.ProxyGeneratorTest$Say

所以默认生成的代理类是继承Proxy且实现了对应的接口的

在这里插入图片描述
查看构造函数,发现只有一个有参数的构造函数InvocationHandler并将其传递给Proxy中存放的h,所以实例化的时候是需要这个的,特别的发现了一个final的say方法被实现了

 public final void say() throws ;
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_FINAL
    Code:
      stack=10, locals=2, args_size=1
         0: aload_0
         1: getfield      #16                 // Field java/lang/reflect/Proxy.h:Ljava/lang/reflect/InvocationHandler;
         4: aload_0
         5: getstatic     #57                 // Field m3:Ljava/lang/reflect/Method;
         8: aconst_null
         9: invokeinterface #28,  4           // InterfaceMethod java/lang/reflect/InvocationHandler.invoke:(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;
        14: pop
        15: return
        16: athrow
        17: astore_1
        18: new           #42                 // class java/lang/reflect/UndeclaredThrowableException
        21: dup
        22: aload_1
        23: invokespecial #45                 // Method java/lang/reflect/UndeclaredThrowableException."<init>":(Ljava/lang/Throwable;)V
        26: athrow
      Exception table:
         from    to  target type
             0    16    16   Class java/lang/Error
             0    16    16   Class java/lang/RuntimeException
             0    16    17   Class java/lang/Throwable
    Exceptions:

解析后得到执行步骤:使用Proxy中的h(InvocationHandler)并完成I的调用操作

所以得到,被jdk动态代理的接口默认会被创建代理的实例所实现,且该接口的实现方式就是转发当前的方法调用操作,其中使用m3记录say这个方法

4. 图解和总结

在这里插入图片描述
jdk的动态代理其实就是class字节码动态生成并被jvm加载,实例化的操作,其所有的方法都会在其中实现并被转发给InvocationHandler

所以当类被加载并生成Class后,后面就是实例化的操作!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值