大佬把JDK动态代理实现讲解得如此通俗易

白癜风哪里治疗最好 https://jbk.39.net/yiyuanzaixian/bjzkbdfyy/ffxbdf/

作为每个Java开发都知道,但又很少能说完全清楚的技术:动态代理。

今天,我们就彻底搞明白它!

深入JDK动态代理实现

基本使用

没有花里胡哨的,就下面的代码:

UserServiceuserService=newUserServiceImpl();UserServiceo=(UserService)Proxy.newProxyInstance(UserService.class.getClassLoader(),newClass[]{UserService.class},newInvocationHandler(){

OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{System.out.println("--before--");Objectinvoke=method.invoke(userService,args);System.out.println("--after--");returninvoke;}});

可以看出,关键在于代理的创建:Proxy.newProxyInstance。后面我们也以这里为入口深入。

关键步骤解析

生成代理类

生成代理类是动态代理中的最复杂的步骤,而真正生成代理类字节码的方法位于:java.lang.reflect.Proxy.ProxyClassFactory#apply。

精简一下方法,主要有以下几个步骤:

//前置校验interfaceClass=Class.forName(intf.getName(),false,loader);if(xxx){thrownewIllegalArgumentException(xxx);}...//数据准备intaccessFlags=Modifier.PUBLIC

Modifier.FINAL;...StringproxyName=proxyPkg+proxyClassNamePrefix+num;...//生成代理类bytesbyte[]proxyClassFile=ProxyGenerator.generateProxyClass(proxyName,interfaces,accessFlags);...//加载returndefineClass0(loader,proxyName,proxyClassFile,0,proxyClassFile.length);

生成代理类与加载是动态代理的核心。

组装ProxyMethod

这里只是将收集到的方法元信息封装为sun.misc.ProxyGenerator.ProxyMethod类存储,并没有真正的生成code。

这里还特地也保存了了hashCode,equals,toString方法。

addProxyMethod(hashCodeMethod,Object.class);addProxyMethod(equalsMethod,Object.class);addProxyMethod(toStringMethod,Object.class);...sigmethods.add(newProxyMethod(name,parameterTypes,returnType,exceptionTypes,fromClass));

组装FieldInfo/MethodInfo

添加构造方法,并根据上一步组装好的ProxyMethod添加成员属性。

在这一步中,会调用sun.misc.ProxyGenerator.ProxyMethod#generateMethod方法,为其生成code。

//生成构造方法this.methods.add(this.generateConstructor());...//生成成员属性fields.add(newFieldInfo(pm.methodFieldName,"Ljava/lang/reflect/Method;",ACC_PRIVATE

ACC_STATIC));//添加方法methods.add(pm.generateMethod());...//添加静态初始化代码块methods.add(generateStaticInitializer());

构造最终类

根据上面几步收集到的信息,生成最终byte数组。

//u4magic;dout.writeInt(0xCAFEBABE);//u2minor_version;dout.writeShort(CLASSFILE_MINOR_VERSION);//u2major_version;dout.writeShort(CLASSFILE_MAJOR_VERSION);cp.write(dout);//(writeconstantpool)//u2access_flags;dout.writeShort(accessFlags);//u2this_class;dout.writeShort(cp.getClass(dotToSlash(className)));//u2super_class;dout.writeShort(cp.getClass(superclassName));...

最终结果

通过配置sun.misc.ProxyGenerator.saveGeneratedFiles=true可以将生成的代理类字节码保存下来。

删除了我们无需关心hashCode,toString等方法后,反编译结果如下:

package


转载请注明:http://www.aierlanlan.com/rzfs/4716.html

  • 上一篇文章:
  •   
  • 下一篇文章: