Java:Jdk动态代理技术解析

Posted 你是小KS

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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后,后面就是实例化的操作!

以上是关于Java:Jdk动态代理技术解析的主要内容,如果未能解决你的问题,请参考以下文章

追踪解析 jdk Proxy 源码

JDK动态代理源码解析——ProxyWeakCacheProxyGenerator

JDK 动态代理(原理 + 代码实现)

JDK动态代理的实现和原理解析(基于JDK1.7)

JDK动态代理的实现和原理解析(基于JDK1.7)

SpringAOP:JDK动态代理