配色: 字号:
Java JDK 动态代理使用及实现原理分析
2016-09-28 | 阅:  转:  |  分享 
  
JavaJDK动态代理使用及实现原理分析

一、什么是代理?

代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。

代理模式UML图:





为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。Java动态代理机制以巧妙的方式近乎完美地实践了代理模式的设计理念。

二、Java动态代理类

Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:

(1)InterfaceInvocationHandler:该接口中仅定义了一个方法

[java]viewplaincopy在CODE上查看代码片派生到我的代码片

publicobjectinvoke(Objectobj,Methodmethod,Object[]args)

在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组。这个抽象方法在代理类中动态实现。

(2)Proxy:该类即为动态代理类,其中主要包含以下内容:

protectedProxy(InvocationHandlerh):构造函数,用于给内部的h赋值。

staticClassgetProxyClass(ClassLoaderloader,Class[]interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。

staticObjectnewProxyInstance(ClassLoaderloader,Class[]interfaces,InvocationHandlerh):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)

所谓DynamicProxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然,这个DynamicProxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。

在使用动态代理类时,我们必须实现InvocationHandler接口

通过这种方式,被代理的对象(RealSubject)可以在运行时动态改变,需要控制的接口(Subject接口)可以在运行时改变,控制的方式(DynamicSubject类)也可以动态改变,从而实现了非常灵活的动态代理关系。

动态代理步骤:

1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法

2.创建被代理的类以及接口

3.通过Proxy的静态方法

newProxyInstance(ClassLoaderloader,Class[]interfaces,InvocationHandlerh)创建一个代理

4.通过代理调用方法



三、JDK的动态代理怎么使用?

1、需要动态代理的接口:

[java]viewplaincopy在CODE上查看代码片派生到我的代码片

packagejiankunking;



/

需要动态代理的接口

/

publicinterfaceSubject

{

/

你好



@paramname

@return

/

publicStringSayHello(Stringname);



/

再见



@return

/

publicStringSayGoodBye();

}



2、需要代理的实际对象

[java]viewplaincopy在CODE上查看代码片派生到我的代码片

packagejiankunking;



/

实际对象

/

publicclassRealSubjectimplementsSubject

{



/

你好



@paramname

@return

/

publicStringSayHello(Stringname)

{

return"hello"+name;

}



/

再见



@return

/

publicStringSayGoodBye()

{

return"goodbye";

}

}



3、调用处理器实现类(有木有感觉这里就是传说中的AOP啊)

[java]viewplaincopy在CODE上查看代码片派生到我的代码片

packagejiankunking;



importjava.lang.reflect.InvocationHandler;

importjava.lang.reflect.Method;





/

调用处理器实现类

每次生成动态代理类对象时都需要指定一个实现了该接口的调用处理器对象

/

publicclassInvocationHandlerImplimplementsInvocationHandler

{



/

这个就是我们要代理的真实对象

/

privateObjectsubject;



/

构造方法,给我们要代理的真实对象赋初值



@paramsubject

/

publicInvocationHandlerImpl(Objectsubject)

{

this.subject=subject;

}



/

该方法负责集中处理动态代理类上的所有方法调用。

调用处理器根据这三个参数进行预处理或分派到委托类实例上反射执行



@paramproxy代理类实例

@parammethod被调用的方法对象

@paramargs调用参数

@return

@throwsThrowable

/

publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable

{

//在代理真实对象前我们可以添加一些自己的操作

System.out.println("在调用之前,我要干点啥呢?");



System.out.println("Method:"+method);



//当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用

ObjectreturnValue=method.invoke(subject,args);



//在代理真实对象后我们也可以添加一些自己的操作

System.out.println("在调用之后,我要干点啥呢?");



returnreturnValue;

}

}

4、测试

[java]viewplaincopy在CODE上查看代码片派生到我的代码片

packagejiankunking;



importjava.lang.reflect.InvocationHandler;

importjava.lang.reflect.Proxy;



/

动态代理演示

/

publicclassDynamicProxyDemonstration

{

publicstaticvoidmain(String[]args)

{

//代理的真实对象

SubjectrealSubject=newRealSubject();



/

InvocationHandlerImpl实现了InvocationHandler接口,并能实现方法调用从代理类到委托类的分派转发

其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用.

即:要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法

/

InvocationHandlerhandler=newInvocationHandlerImpl(realSubject);





ClassLoaderloader=handler.getClass().getClassLoader();

Class[]interfaces=realSubject.getClass().getInterfaces();

/

该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例

/

Subjectsubject=(Subject)Proxy.newProxyInstance(loader,interfaces,handler);



System.out.println("动态代理对象的类型:"+subject.getClass().getName());



Stringhello=subject.SayHello("jiankunking");

System.out.println(hello);

//Stringgoodbye=subject.SayGoodBye();

//System.out.println(goodbye);

}



}



5、输出结果如下:



四、动态代理怎么实现的?

从使用代码中可以看出,关键点在:

[java]viewplaincopy在CODE上查看代码片派生到我的代码片

Subjectsubject=(Subject)Proxy.newProxyInstance(loader,interfaces,handler);

通过跟踪提示代码可以看出:当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用。

也就是说,当代码执行到:

subject.SayHello("jiankunking")这句话时,会自动调用InvocationHandlerImpl的invoke方法。这是为啥呢?



======================横线之间的是代码跟分析的过程,不想看的朋友可以直接看结论=====================================

以下代码来自:JDK1.8.0_92

既然生成代理对象是用的Proxy类的静态方newProxyInstance,那么我们就去它的源码里看一下它到底都做了些什么?

[java]viewplaincopy在CODE上查看代码片派生到我的代码片

publicstaticObjectnewProxyInstance(ClassLoaderloader,

Class[]interfaces,

InvocationHandlerh)

throwsIllegalArgumentException

{

//检查h不为空,否则抛异常

Objects.requireNonNull(h);



finalClass[]intfs=interfaces.clone();

finalSecurityManagersm=System.getSecurityManager();

if(sm!=null){

checkProxyAccess(Reflection.getCallerClass(),loader,intfs);

}



/

获得与指定类装载器和一组接口相关的代理类类型对象

/

Classcl=getProxyClass0(loader,intfs);



/

通过反射获取构造函数对象并生成代理类实例

/

try{

if(sm!=null){

checkNewProxyPermission(Reflection.getCallerClass(),cl);

}

//获取代理对象的构造方法(也就是$Proxy0(InvocationHandlerh))

finalConstructorcons=cl.getConstructor(constructorParams);

finalInvocationHandlerih=h;

if(!Modifier.isPublic(cl.getModifiers())){

AccessController.doPrivileged(newPrivilegedAction(){

publicVoidrun(){

cons.setAccessible(true);

returnnull;

}

});

}

//生成代理类的实例并把InvocationHandlerImpl的实例传给它的构造方法

returncons.newInstance(newObject[]{h});

}catch(IllegalAccessException|InstantiationExceptione){

thrownewInternalError(e.toString(),e);

}catch(InvocationTargetExceptione){

Throwablet=e.getCause();

if(tinstanceofRuntimeException){

throw(RuntimeException)t;

}else{

thrownewInternalError(t.toString(),t);

}

}catch(NoSuchMethodExceptione){

thrownewInternalError(e.toString(),e);

}

}

我们再进去getProxyClass0方法看一下:

[java]viewplaincopy在CODE上查看代码片派生到我的代码片

/

Generateaproxyclass.MustcallthecheckProxyAccessmethod

toperformpermissionchecksbeforecallingthis.

/

privatestaticClassgetProxyClass0(ClassLoaderloader,

Class...interfaces){

if(interfaces.length>65535){

thrownewIllegalArgumentException("interfacelimitexceeded");

}



//Iftheproxyclassdefinedbythegivenloaderimplementing

//thegiveninterfacesexists,thiswillsimplyreturnthecachedcopy;

//otherwise,itwillcreatetheproxyclassviatheProxyClassFactory

returnproxyClassCache.get(loader,interfaces);

}

真相还是没有来到,继续,看一下proxyClassCache

[java]viewplaincopy在CODE上查看代码片派生到我的代码片

/

acacheofproxyclasses

/

privatestaticfinalWeakCache[],Class>

proxyClassCache=newWeakCache<>(newKeyFactory(),newProxyClassFactory());

奥,原来用了一下缓存啊

那么它对应的get方法啥样呢?

[java]viewplaincopy在CODE上查看代码片派生到我的代码片

/

Look-upthevaluethroughthecache.Thisalwaysevaluatesthe

{@codesubKeyFactory}functionandoptionallyevaluates

{@codevalueFactory}functionifthereisnoentryinthecacheforgiven

pairof(key,subKey)ortheentryhasalreadybeencleared.



@paramkeypossiblynullkey

@paramparameterparameterusedtogetherwithkeytocreatesub-keyand

value(shouldnotbenull)

@returnthecachedvalue(nevernull)

@throwsNullPointerExceptionif{@codeparameter}passedinor

{@codesub-key}calculatedby

{@codesubKeyFactory}or{@codevalue}

calculatedby{@codevalueFactory}isnull.

/

publicVget(Kkey,Pparameter){

Objects.requireNonNull(parameter);



expungeStaleEntries();



ObjectcacheKey=CacheKey.valueOf(key,refQueue);



//lazilyinstallthe2ndlevelvaluesMapfortheparticularcacheKey

ConcurrentMap>valuesMap=map.get(cacheKey);

if(valuesMap==null){

//putIfAbsent这个方法在key不存在的时候加入一个值,如果key存在就不放入

ConcurrentMap>oldValuesMap

=map.putIfAbsent(cacheKey,

valuesMap=newConcurrentHashMap<>());

if(oldValuesMap!=null){

valuesMap=oldValuesMap;

}

}



//createsubKeyandretrievethepossibleSupplierstoredbythat

//subKeyfromvaluesMap

ObjectsubKey=Objects.requireNonNull(subKeyFactory.apply(key,parameter));

Suppliersupplier=valuesMap.get(subKey);

Factoryfactory=null;



while(true){

if(supplier!=null){

//suppliermightbeaFactoryoraCacheValueinstance

Vvalue=supplier.get();

if(value!=null){

returnvalue;

}

}

//elsenosupplierincache

//orasupplierthatreturnednull(couldbeaclearedCacheValue

//oraFactorythatwasn''tsuccessfulininstallingtheCacheValue)



//lazilyconstructaFactory

if(factory==null){

factory=newFactory(key,parameter,subKey,valuesMap);

}



if(supplier==null){

supplier=valuesMap.putIfAbsent(subKey,factory);

if(supplier==null){

//successfullyinstalledFactory

supplier=factory;

}

//elseretrywithwinningsupplier

}else{

if(valuesMap.replace(subKey,supplier,factory)){

//successfullyreplaced

//clearedCacheEntry/unsuccessfulFactory

//withourFactory

supplier=factory;

}else{

//retrywithcurrentsupplier

supplier=valuesMap.get(subKey);

}

}

}

}



我们可以看到它调用了supplier.get();获取动态代理类,其中supplier是Factory,这个类定义在WeakCach的内部。

来瞅瞅,get里面又做了什么?

[java]viewplaincopy在CODE上查看代码片派生到我的代码片

publicsynchronizedVget(){//serializeaccess

//re-check

Suppliersupplier=valuesMap.get(subKey);

if(supplier!=this){

//somethingchangedwhilewewerewaiting:

//mightbethatwewerereplacedbyaCacheValue

//orwereremovedbecauseoffailure->

//returnnulltosignalWeakCache.get()toretry

//theloop

returnnull;

}

//elsestillus(supplier==this)



//createnewvalue

Vvalue=null;

try{

value=Objects.requireNonNull(valueFactory.apply(key,parameter));

}finally{

if(value==null){//removeusonfailure

valuesMap.remove(subKey,this);

}

}

//theonlypathtoreachhereiswithnon-nullvalue

assertvalue!=null;



//wrapvaluewithCacheValue(WeakReference)

CacheValuecacheValue=newCacheValue<>(value);



//tryreplacinguswithCacheValue(thisshouldalwayssucceed)

if(valuesMap.replace(subKey,this,cacheValue)){

//putalsoinreverseMap

reverseMap.put(cacheValue,Boolean.TRUE);

}else{

thrownewAssertionError("Shouldnotreachhere");

}



//successfullyreplaceduswithnewCacheValue->returnthevalue

//wrappedbyit

returnvalue;

}

}



发现重点还是木有出现,但我们可以看到它调用了valueFactory.apply(key,parameter)方法:

[java]viewplaincopy在CODE上查看代码片派生到我的代码片

/

Afactoryfunctionthatgenerates,definesandreturnstheproxyclassgiven

theClassLoaderandarrayofinterfaces.

/

privatestaticfinalclassProxyClassFactory

implementsBiFunction[],Class>

{

//prefixforallproxyclassnames

privatestaticfinalStringproxyClassNamePrefix="$Proxy";



//nextnumbertouseforgenerationofuniqueproxyclassnames

privatestaticfinalAtomicLongnextUniqueNumber=newAtomicLong();



@Override

publicClassapply(ClassLoaderloader,Class[]interfaces){



Map,Boolean>interfaceSet=newIdentityHashMap<>(interfaces.length);

for(Classintf:interfaces){

/

Verifythattheclassloaderresolvesthenameofthis

interfacetothesameClassobject.

/

ClassinterfaceClass=null;

try{

interfaceClass=Class.forName(intf.getName(),false,loader);

}catch(ClassNotFowww.shanxiwang.netundExceptione){

}

if(interfaceClass!=intf){

thrownewIllegalArgumentException(

intf+"isnotvisiblefromclassloader");

}

/

VerifythattheClassobjectactuallyrepresentsan

interface.

/

if(!interfaceClass.isInterface()){

thrownewIllegalArgumentException(

interfaceClass.getName()+"isnotaninterface");

}

/

Verifythatthisinterfaceisnotaduplicate.

/

if(interfaceSet.put(interfaceClass,Boolean.TRUE)!=null){

thrownewIllegalArgumentException(

"repeatedinterface:"+interfaceClass.getName());

}

}



StringproxyPkg=null;//packagetodefineproxyclassin

intaccessFlags=Modifier.PUBLIC|Modifier.FINAL;



/

Recordthepackageofanon-publicproxyinterfacesothatthe

proxyclasswillbedefinedinthesamepackage.Verifythat

allnon-publicproxyinterfacesareinthesamepackage.

/

for(Classintf:interfaces){

intflags=intf.getModifiers();

if(!Modifier.isPublic(flags)){

accessFlags=Modifier.FINAL;

Stringname=intf.getName();

intn=name.lastIndexOf(''.'');

Stringpkg=((n==-1)?"":name.substring(0,n+1));

if(proxyPkg==null){

proxyPkg=pkg;

}elseif(!pkg.equals(proxyPkg)){

thrownewIllegalArgumentException(

"non-publicinterfacesfromdifferentpackages");

}

}

}



if(proxyPkg==null){

//ifnonon-publicproxyinterfaces,usecom.sun.proxypackage

proxyPkg=ReflectUtil.PROXY_PACKAGE+".";

}



/

Chooseanamefortheproxyclasstogenerate.

/

longnum=nextUniqueNumber.getAndIncrement();

StringproxyName=proxyPkg+proxyClassNamePrefix+num;



/

Generatethespecifiedproxyclass.

/

byte[]proxyClassFile=ProxyGenerator.generateProxyClass(

proxyName,interfaces,accessFlags);

try{

returndefineClass0(loader,proxyName,

proxyClassFile,0,proxyClassFile.length);

}catch(ClassFormatErrore){

/

AClassFormatErrorheremeansthat(barringbugsinthe

proxyclassgenerationcode)therewassomeother

invalidaspectoftheargumentssuppliedtotheproxy

classcreation(suchasvirtualmachinelimitations

exceeded).

/

thrownewIllegalArgumentException(e.toString());

}

}

}

通过看代码终于找到了重点:

[java]viewplaincopy在CODE上查看代码片派生到我的代码片

//生成字节码

byte[]proxyClassFile=ProxyGenerator.generateProxyClass(proxyName,interfaces,accessFlags);

那么接下来我们也使用测试一下,使用这个方法生成的字节码是个什么样子:

[java]viewplaincopy在CODE上查看代码片派生到我的代码片

packagejiankunking;



importsun.misc.ProxyGenerator;



importjava.io.File;

importjava.io.FileNotFoundException;

importjava.io.FileOutputStream;

importjava.io.IOException;

importjava.lang.reflect.InvocationHandler;

importjava.lang.reflect.Proxy;



/

动态代理演示

/

publicclassDynamicProxyDemonstration

{

publicstaticvoidmain(String[]args)

{

//代理的真实对象

SubjectrealSubject=newRealSubject();



/

InvocationHandlerImpl实现了InvocationHandler接口,并能实现方法调用从代理类到委托类的分派转发

其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用.

即:要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法

/

InvocationHandlerhandler=newInvocationHandlerImpl(realSubject);



ClassLoaderloader=handler.getClass().getClassLoader();

Class[]interfaces=realSubject.getClass().getInterfaces();

/

该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例

/

Subjectsubject=(Subject)Proxy.newProxyInstance(loader,interfaces,handler);



System.out.println("动态代理对象的类型:"+subject.getClass().getName());



Stringhello=subject.SayHello("jiankunking");

System.out.println(hello);

//将生成的字节码保存到本地,

createProxyClassFile();

}

privatestaticvoidcreateProxyClassFile(){

Stringname="ProxySubject";

byte[]data=ProxyGenerator.generateProxyClass(name,newClass[]{Subject.class});

FileOutputStreamout=null;

try{

out=newFileOutputStream(name+".class");

System.out.println((newFile("hello")).getAbsolutePath());

out.write(data);

}catch(FileNotFoundExceptione){

e.printStackTrace();

}catch(IOExceptione){

e.printStackTrace();

}finally{

if(null!=out)try{

out.close();

}catch(IOExceptione){

e.printStackTrace();

}

}

}



}

我们用jd-jui工具将生成的字节码反编译:

[java]viewplaincopy在CODE上查看代码片派生到我的代码片

importjava.lang.reflect.InvocationHandler;

importjava.lang.reflect.Method;

importjava.lang.reflect.Proxy;

importjava.lang.reflect.UndeclaredThrowableException;

importjiankunking.Subject;



publicfinalclassProxySubject

extendsProxy

implementsSubject

{

privatestaticMethodm1;

privatestaticMethodm3;

privatestaticMethodm4;

privatestaticMethodm2;

privatestaticMethodm0;



publicProxySubject(InvocationHandlerparamInvocationHandler)

{

super(paramInvocationHandler);

}



publicfinalbooleanequals(ObjectparamObject)

{

try

{

return((Boolean)this.h.invoke(this,m1,newObject[]{paramObject})).booleanValue();

}

catch(Error|RuntimeExceptionlocalError)

{

throwlocalError;

}

catch(ThrowablelocalThrowable)

{

thrownewUndeclaredThrowableException(localThrowable);

}

}



publicfinalStringSayGoodBye()

{

try

{

return(String)this.h.invoke(this,m3,null);

}

catch(Error|RuntimeExceptionlocalError)

{

throwlocalError;

}

catch(ThrowablelocalThrowable)

{

thrownewUndeclaredThrowableException(localThrowable);

}

}



publicfinalStringSayHello(StringparamString)

{

try

{

return(String)this.h.invoke(this,m4,newObject[]{paramString});

}

catch(Error|RuntimeExceptionlocalError)

{

throwlocalError;

}

catch(ThrowablelocalThrowable)

{

thrownewUndeclaredThrowableException(localThrowable);

}

}



publicfinalStringtoString()

{

try

{

return(String)this.h.invoke(this,m2,null);

}

catch(Error|RuntimeExceptionlocalError)

{

throwlocalError;

}

catch(ThrowablelocalThrowable)

{

thrownewUndeclaredThrowableException(localThrowable);

}

}



publicfinalinthashCode()

{

try

{

return((Integer)this.h.invoke(this,m0,null)).intValue();

}

catch(Error|RuntimeExceptionlocalError)

{

throwlocalError;

}

catch(ThrowablelocalThrowable)

{

thrownewUndeclaredThrowableException(localThrowable);

}

}



static

{

try

{

m1=Class.forName("java.lang.Object").getMethod("equals",newClass[]{Class.forName("java.lang.Object")});

m3=Class.forName("jiankunking.Subject").getMethod("SayGoodBye",newClass[0]);

m4=Class.forName("jiankunking.Subject").getMethod("SayHello",newClass[]{Class.forName("java.lang.String")});

m2=Class.forName("java.lang.Object").getMethod("toString",newClass[0]);

m0=Class.forName("java.lang.Object").getMethod("hashCode",newClass[0]);

return;

}

catch(NoSuchMethodExceptionlocalNoSuchMethodException)

{

thrownewNoSuchMethodError(localNoSuchMethodException.getMessage());

}

catch(ClassNotFoundExceptionlocalClassNotFoundException)

{

thrownewNoClassDefFoundError(localClassNotFoundException.getMessage());

}

}

}



这就是最终真正的代理类,它继承自Proxy并实现了我们定义的Subject接口

也就是说:

[java]viewplaincopy在CODE上查看代码片派生到我的代码片

Subjectsubject=(Subject)Proxy.newProxyInstance(loader,interfaces,handler);

这里的subject实际是这个类的一个实例,那么我们调用它的:

[java]viewplaincopy在CODE上查看代码片派生到我的代码片

publicfinalStringSayHello(StringparamString)

就是调用我们定义的InvocationHandlerImpl的invoke方法:



======================横线之间的是代码跟分析的过程,不想看的朋友可以直接看结论=====================================

五、结论

到了这里,终于解答了:

subject.SayHello("jiankunking")这句话时,为什么会自动调用InvocationHandlerImpl的invoke方法?



因为JDK生成的最终真正的代理类,它继承自Proxy并实现了我们定义的Subject接口,在实现Subject接口方法的内部,通过反射调用了

InvocationHandlerImpl的invoke方法。

通过分析代码可以看出Java动态代理,具体有如下四步骤:

通过实现InvocationHandler接口创建自己的调用处理器;

通过为Proxy类指定ClassLoader对象和一组interface来创建动态代理类;

通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;

通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。

献花(0)
+1
(本文系网络学习天...首藏)