jdk代理和动态代理的区别,jdk动态代理为什么只能代理接口

  jdk代理和动态代理的区别,jdk动态代理为什么只能代理接口

  JAVA动态代理在内部实现了一种代理设计模式。代理模式为目标对象提供一个代理来控制对实际对象的访问。在某些情况下,客户端不希望或不能直接引用另一个对象,代理对象可以充当客户端和目标对象之间的中介。

  为了保持行为一致,代理类和实际的委托类通常实现同一个接口,所以在访问者的眼中它们没有区别。

  代理模式类图

  常见的代理有:

  1)远程代理:为位于不同地址空间的对象提供本地代表对象,如RMI中的存根。

  2)虚拟代理:根据需要延迟加载一个消耗大量资源或者比较复杂的对象,只有在真正需要的时候才创建。

  3)保护或访问代理:控制对对象的访问权限。

  4)智能引用代理:提供比目标对象更多的服务和功能。

  通过代理类中间层,可以有效控制对实际委托类对象的直接访问,也可以隐藏和保护实际对,实现不同的控制策略,从而在设计上获得更大的灵活性。

  第二个动态代理使用JAVA动态代理机制,巧妙的实现了代理模式的设计理念。

  动态代理类图

  动态agent在ProxySubject和RealSubject之间增加了InvocationHandler,这是一种间接的通信,增加了灵性。比如这个中间层可以实现为框架,RealSubject可以通过xml文件直接调用。

  在普通设计中,我们一般不使用动态代理。但是,在一些框架设计中,动态代理非常重要,例如RMI和EJB。

  查看plain interface subject { publicvoidosomething();} classrealpubjectimplementssubject { publicviddosomething(){ system . out . println( calldoSomething());} } class proxyhandlermimplementsinvocationhandler { privateObjectproxied;publicProxyHandler(Objectproxied){ this . proxied=proxied;} public Object invoke(Object proxy,Methodmethod,Object[]args)throws row able { return method . invoke(proxied,args);}}

  查看plain import Java . lang . reflect . invocation handler;import Java . lang . reflect . method;import Java . lang . reflect . proxy;import sun . misc . proxy generator;import Java . io . *;publicclassDynamicProxy { publicstaticvoidmain(string args[]){ real subject real=new real subject();SubjectproxySubject=(Subject)proxy . newproxyinstance(Subject . class . getclass loader()、newClass[]{Subject.class}、newProxyHandler(real));proxy subject . do something();//writeproxysubjectclassbinarydatofilecreateproxyclassfile();} publistaticvoidcreateproxyclass file(){ string name= proxy subject ;byte[]data=proxy generator . generate proxy class(name,new class[]{ subject . class });请尝试{ file output stream out=newfile output stream(name 。类’);out.write(数据);out . close();} catch(exception one){ e . printstacktrace();}}}三个动态代理内部实现Proxy类的getProxyClass方法,调用ProxyGenerator的generateProxyClass方法生成ProxySubject.class的二进制数据:

  public static byte[]generate proxy Class(最终字符串名称,Class[]接口)

  我们可以导入sun.misc.ProxyGenerator,调用generateProxyClass方法生成二进制数据,然后写入文件,最后通过反编译工具检查内部实现原理。

  反编译的ProxySubject.java:

  查看纯导入Java。郎。反思。*;publicfinalclassproxysubjectextendsproxyimentssobject { privatesticmethod m 1;privatesticmethod m0 privatesticmethod m3 privatesticmethod m2 publicproxysubject(InvocationHandlerinvocationhandler){ super(调用处理程序);} publicfinalbooleanvequals(object obj){ try { return((Boolean)super。h . invoke(this,m1,newObject[]{obj}).布尔值();} catch(Error _ ex){ } catch(Throwablethrowable){ thrownewUndeclaredThrowableException(throwable);} } publicfinalintashcode(){ try { return((Integer)super。调用(this,m0,null)).int value();} catch(Error _ ex){ } catch(Throwablethrowable){ thrownewUndeclaredThrowableException(throwable);} } publicfilvoiddosomething(){ try { super。h . invoke(this,m3,null);返回;} catch(Error _ ex){ } catch(Throwablethrowable){ thrownewUndeclaredThrowableException(throwable);} } publicfinalStringtoString(){ try { return(String)super。h . invoke(this,m2,null);} catch(Error _ ex){ } catch(Throwablethrowable){ thrownewUndeclaredThrowableException(throwable);} } static { try { m1=class。forname( Java。郎。对象’).getMethod(equals ,新类[]{ class。forname( Java。郎。object’));m0=类别。forname( Java。郎。对象’).getMethod(hashCode ,new class[0]);m3=Class.forName(“主题”).getMethod(doSomething ,new class[0]);m2=类别。forname( Java。郎。对象’).getMethod(toString ,new class[0]);} catch(nosuchmethodexception noschmethodexception){ thrownewNoSuchMethodError(nosuchmethodexception。getmessage());} catch(classnotfoundexception classnotfoundexception){ thrownewNoClassDefFoundError(classnotfoundexception。getmessage());}}} 通过ProxySubject.java,我们可以看到动态代理的内部是如何实现的,并且我们可以实现自己的一个动态代理生成器。

  邻近发电机内部是如何生成班级二进制数据,可以参考源代码。

  查看plainprivatebyte[]生成Java的类file(){/* * recordthaproxymethodsssareneededforthehashcode,equals,*和tostringmethodsof。郎。对象。thisisdonebefore * themethodsfrom * Java。郎。objecttakepiceverduplicatemethodsfrom *代理接口。*/addProxyMethod(hashcode method,object。类);addProxyMethod(equalsMethod,object。类);addProxyMethod(toStringMethod,object。类);/* * Nowrecordallofthemethodsfromtheproxyinterfaces,给定*早期接口重复出现重复字符*方法. for */for(inti=0;我接口。长度;I){ Method[]方法=接口[I].get方法();for(intj=0;j方法。长度;j ){addProxyMethod(方法[j],接口【我】);} }/* *具有相同签名的foreachsetofproxymethods,*的验证方法的返回类型是否兼容. for(列出代理方法sigmethods:代理方法。values()){ check返回类型(sigmethods);}/*================================================*第二步:assembliefieldinfoandmethodinfostructsforallof * fieldsandmethods intheclasswearegeneration .*/尝试{方法。add(生成构造函数());for(列出代理方法sigmethods:代理方法。values()){ for(proxy Method pm:sigmethods){//addstaticfieldformethod smethodobjectfields。添加(新字段信息(pm。方法字段名称,“Ljava/lang/reflect/Method;ACC _ PRIVATE ACC _ STATIC));//generatecodeforproxymethodandadditmethods。添加(下午。生成方法());} }方法。add(generatestacinitializer());} catch(IOExceptione){ thrownewInternalError( unexpectdi/OE exception );}/*=========================================================*第三步:Writethefinalclassfile .*//* * makesurethaconstantpoolindexesarereservedforthe *以下项目itemsbeforestartingtowritefinalclassfile .*/CP。getclass(dotToSlash(类名));比较getclass(超类名);for(inti=0;我接口。长度;I){ CP。get类(dotToSlash(interfaces[I]).getName()));}/* * disallownewconstantpooladditionsbeyondthipoint,因为* weareabouttowritefinalconstantpooltable .*/CP。set readonly();ByteArrayOutputStreambout=newByteArrayOutputStream();DataOutputStreamdout=newDataOutputStream(bout);请尝试使用"类文件"结构的{/* * writealltheitems .*参见JVMs第4.1节。*///u 4魔;杜特。写int(0x cafe babe);//U2 minor _ version;杜特。写短(类file _ MINOR _ VERSION);//U2主版本;杜特。写短(类文件_专业_版本);比较写(dout);//(writeconstantpool)//U2 access _ flags;杜特。写短(ACC _ PUBLIC ACC _ FINAL ACC _ SUPER);//U2 this _ class;杜特。写短(CP。getclass(dotToSlash(类名)));//U2 super _ class;杜特。写短(CP。get class(超类名));//U2接口数_计数;dout.writeShort(接口。长度);//U2接口[interfaces _ count];for(inti=0;我接口。长度;我){ dout。写短(CP。get类(dotToSlash(interfaces[I]).getName()))))));}//U2 fields _ count;杜特。写短(字段。size());//field _ info fields[fields _ count];for(FieldInfof:fields){ f . write(dout);}//U2 methods _ count;杜特。写短(方法。size());//method _ info方法[methods _ count];for(method info:methods){ m . write(dout);}//U2属性_计数;杜特。写短(0);//(noclassfileattributesforproxyclass)} catch(io异常){ thrownewInternalError( unexpectdi/OE异常);}回回合。tobytearray();

  http://博客。csdn。net/column/details/内核。html # http://博客。csdn。net/lycb _ gz/article/details/6975720http://博客。csdn。net/更多窗口/文章/详情/6976468

  转载的文章。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

相关文章阅读

  • ubuntu18.04安装jdk8,ubuntu中安装jdk
  • ubuntu18.04安装jdk8,ubuntu中安装jdk,Ubuntu 安装 JDK8 的两种方法(总结)
  • JDK1.8安装教程,安装配置jdk1.8
  • JDK1.8安装教程,安装配置jdk1.8,2020JDK1.8安装教程详解(一次就可安装成功)
  • ,,jdk8使用stream实现两个list集合合并成一个(对象属性的合并)
  • ,,IntelliJ IDEA之配置JDK的4种方式(小结)
  • java代理模式详解,java代理模式的典型例子,java代理模式(jdk proxy)
  • java中spi有什么作用,jdk的spi机制
  • java中spi有什么作用,jdk的spi机制,一文搞懂Java的SPI机制(推荐)
  • ,,详解JDK自带javap命令反编译class文件和Jad反编译class文件(推荐使用jad)
  • ,,JAVA帮助文档全系列 JDK1.5 JDK1.6 JDK1.7 官方中英完整版整理
  • ,,JAVA JDK8 List分组的实现和用法
  • idea配置tomcat和jdk,idea配置本地gradle
  • 简单叙述一下jdk环境变量的配置,jdk环境变量配置是干什么的
  • 建立Java开发环境,安装JDK,一般需要设置环境变量,在安装完JDK后,需要在环境变量中配置
  • 留言与评论(共有 条评论)
       
    验证码: