java高级---->Java动态代理的原理
本文内容纲要:
-动态代理的简要说明
-一、InvocationHandler(interface)的描述:
-二、Proxy(Class)的描述:
-简单的Java代理
-一、先定义一个接口Interface,添加两个方法。
-二、定义一个真实的实现上述接口的类,RealObject:
-三、定义一个代理对象,也实现了上述的Interface接口:
-四、SimpleMain在Main方法中,测试上述的结果:
-五、运行的结果如下:
-Java的动态代理
-一、创建一个继承了InvocationHandler的处理器:DynamicProxyHandler
-二、我们写一个测试的Main方法,DynamicProxyMain:
-三、运行结果如下:
-Java动态代理的原理
-一、动态代理的关键代码就是Proxy.newProxyInstance(classLoader,interfaces,handler),我们跟进源代码看看:
-二、我们看一下newInstance方法的源代码:
-三、当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的invoke方法来进行调用。
-友情链接
Java动态代理机制的出现,使得Java开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类。代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执行的过程中,开发人员还可以按需调整委托类对象及其功能,这是一套非常灵活有弹性的代理框架。下面我们开始动态代理的学习。
目录导航
- 动态代理的简要说明
- 简单的Java代理
- Java的动态代理
- Java动态代理的原理
- 友情链接
动态代理的简要说明
在java的动态代理机制中,有两个重要的类或接口,一个是InvocationHandler(Interface)、另一个则是Proxy(Class)。
一、InvocationHandler(interface)的描述:
InvocationHandleristheinterfaceimplementedbytheinvocationhandlerofaproxyinstance.
Eachproxyinstancehasanassociatedinvocationhandler.Whenamethodisinvokedonaproxyinstance,themethodinvocationisencodedanddispatchedtotheinvokemethodofitsinvocationhandler.
每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的invoke方法来进行调用。我们来看看InvocationHandler这个接口的唯一一个方法invoke方法:
Objectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable
这个方法接收三个参数和返回一个Object类型,它们分别代表的意思如下:
- proxy:指代我们所代理的那个真实对象
- method:指代的是我们所要调用真实对象的方法的Method对象
- args:指代的是调用真实对象某个方法时接受的参数
返回的Object是指真实对象方法的返回类型,以上会在接下来的例子中加以深入理解。
thevaluetoreturnfromthemethodinvocationontheproxyinstance.
二、Proxy(Class)的描述:
Proxyprovidesstaticmethodsforcreatingdynamicproxyclassesandinstances,anditisalsothesuperclassofalldynamicproxyclassescreatedbythosemethods.
Proxy这个类的作用就是用来动态创建一个代理对象。我们经常使用的是newProxyInstance这个方法:
publicstaticObjectnewProxyInstance(ClassLoaderloader,Class<?>[]interfaces,InvocationHandlerh)throwsIllegalArgumentException
参数的理解:
//一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
loader-theclassloadertodefinetheproxyclass
//一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口
interfaces-thelistofinterfacesfortheproxyclasstoimplement
//一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
h-theinvocationhandlertodispatchmethodinvocationsto
返回结果的理解:一个代理对象的实例
aproxyinstancewiththespecifiedinvocationhandlerofaproxyclassthatisdefinedbythespecifiedclassloaderandthatimplementsthespecifiedinterfaces
简单的Java代理
我们创建一个Java项目用于对动态代理的测试与理解,项目结构如下:
一、先定义一个接口Interface,添加两个方法。
packagecom.huhx.proxy;
publicinterfaceInterface{
voidgetMyName();
StringgetNameById(Stringid);
}
二、定义一个真实的实现上述接口的类,RealObject:
packagecom.huhx.proxy;
publicclassRealObjectimplementsInterface{
@Override
publicvoidgetMyName(){
System.out.println("mynameishuhx");
}
@Override
publicStringgetNameById(Stringid){
System.out.println("argumentid:"+id);
return"huhx";
}
}
三、定义一个代理对象,也实现了上述的Interface接口:
packagecom.huhx.proxy;
publicclassSimpleProxyimplementsInterface{
privateInterfaceproxied;
publicSimpleProxy(Interfaceproxied){
this.proxied=proxied;
}
@Override
publicvoidgetMyName(){
System.out.println("proxygetmyname");
proxied.getMyName();
}
@Override
publicStringgetNameById(Stringid){
System.out.println("proxygetnamebyid");
returnproxied.getNameById(id);
}
}
四、SimpleMain在Main方法中,测试上述的结果:
packagecom.huhx.proxy;
publicclassSimpleMain{
privatestaticvoidconsume(Interfaceiface){
iface.getMyName();
Stringname=iface.getNameById("1");
System.out.println("name:"+name);
}
publicstaticvoidmain(String[]args){
consume(newRealObject());
System.out.println("========================================================");
consume(newSimpleProxy(newRealObject()));
}
}
五、运行的结果如下:
mynameishuhx
argumentid:1
name:huhx
========================================================
proxygetmyname
mynameishuhx
proxygetnamebyid
argumentid:1
name:huhx
Java的动态代理
完成了上述简单的Java代理,现在我们开始学习Java的动态代理,它比代理的思想更向前一步,因为它可以动态地创建代理并动态的处理对所代理方法的调用。在动态代理上所做的所有调用都会被重定向到单一的调用处理器上,它的工作是揭示调用的类型并确定相应的对策。下面我们通过案例来加深Java动态代理的理解:
一、创建一个继承了InvocationHandler的处理器:DynamicProxyHandler
packagecom.huhx.dynamicproxy;
importjava.lang.reflect.InvocationHandler;
importjava.lang.reflect.Method;
importjava.util.Arrays;
publicclassDynamicProxyHandlerimplementsInvocationHandler{
privateObjectproxied;
publicDynamicProxyHandler(Objectproxied){
System.out.println("dynamicproxyhandlerconstuctor:"+proxied.getClass());
this.proxied=proxied;
}
@Override
publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{
System.out.println("dynamicproxyname:"+proxy.getClass());
System.out.println("method:"+method.getName());
System.out.println("args:"+Arrays.toString(args));
ObjectinvokeObject=method.invoke(proxied,args);
if(invokeObject!=null){
System.out.println("invokeobject:"+invokeObject.getClass());
}else{
System.out.println("invokeobjectisnull");
}
returninvokeObject;
}
}
二、我们写一个测试的Main方法,DynamicProxyMain:
packagecom.huhx.dynamicproxy;
importjava.lang.reflect.InvocationHandler;
importjava.lang.reflect.Proxy;
importcom.huhx.proxy.Interface;
importcom.huhx.proxy.RealObject;
publicclassDynamicProxyMain{
publicstaticvoidconsumer(Interfaceiface){
iface.getMyName();
Stringname=iface.getNameById("1");
System.out.println("name:"+name);
}
publicstaticvoidmain(String[]args)throwsException,SecurityException,Throwable{
RealObjectrealObject=newRealObject();
consumer(realObject);
System.out.println("==============================");
//动态代理
ClassLoaderclassLoader=Interface.class.getClassLoader();
Class<?>[]interfaces=newClass[]{Interface.class};
InvocationHandlerhandler=newDynamicProxyHandler(realObject);
Interfaceproxy=(Interface)Proxy.newProxyInstance(classLoader,interfaces,handler);
System.out.println("indynamicproxyMainproxy:"+proxy.getClass());
consumer(proxy);
}
}
三、运行结果如下:
mynameishuhx
argumentid:1
name:huhx
==============================
dynamicproxyhandlerconstuctor:classcom.huhx.proxy.RealObject
indynamicproxyMainproxy:classcom.sun.proxy.$Proxy0
dynamicproxyname:classcom.sun.proxy.$Proxy0
method:getMyName
args:null
mynameishuhx
invokeobjectisnull
dynamicproxyname:classcom.sun.proxy.$Proxy0
method:getNameById
args:[1]
argumentid:1
invokeobject:classjava.lang.String
name:huhx
从以上输出结果,我们可以得出以下结论:
- 与代理对象相关联的InvocationHandler,只有在代理对象调用方法时,才会执行它的invoke方法
- invoke的三个参数的理解:Objectproxy是代理的对象,Methodmethod是真实对象中调用方法的Method类,Object[]args是真实对象中调用方法的参数
Java动态代理的原理
一、动态代理的关键代码就是Proxy.newProxyInstance(classLoader,interfaces,handler),我们跟进源代码看看:
publicstaticObjectnewProxyInstance(ClassLoaderloader,Class<?>[]interfaces,InvocationHandlerh)throwsIllegalArgumentException{
//handler不能为空
if(h==null){
thrownewNullPointerException();
}
finalClass<?>[]intfs=interfaces.clone();
finalSecurityManagersm=System.getSecurityManager();
if(sm!=null){
checkProxyAccess(Reflection.getCallerClass(),loader,intfs);
}
/*
*Lookuporgeneratethedesignatedproxyclass.
*/
//通过loader和接口,得到代理的Class对象
Class<?>cl=getProxyClass0(loader,intfs);
/*
*Invokeitsconstructorwiththedesignatedinvocationhandler.
*/
try{
finalConstructor<?>cons=cl.getConstructor(constructorParams);
finalInvocationHandlerih=h;
if(sm!=null&&ProxyAccessHelper.needsNewInstanceCheck(cl)){
//createproxyinstancewithdoPrivilegeastheproxyclassmay
//implementnon-publicinterfacesthatrequiresaspecialpermission
returnAccessController.doPrivileged(newPrivilegedAction<Object>(){
publicObjectrun(){
returnnewInstance(cons,ih);
}
});
}else{
//创建代理对象的实例
returnnewInstance(cons,ih);
}
}catch(NoSuchMethodExceptione){
thrownewInternalError(e.toString());
}
}
二、我们看一下newInstance方法的源代码:
privatestaticObjectnewInstance(Constructor<?>cons,InvocationHandlerh){
try{
returncons.newInstance(newObject[]{h});
}catch(IllegalAccessException|InstantiationExceptione){
thrownewInternalError(e.toString());
}catch(InvocationTargetExceptione){
Throwablet=e.getCause();
if(tinstanceofRuntimeException){
throw(RuntimeException)t;
}else{
thrownewInternalError(t.toString());
}
}
}
三、当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的invoke方法来进行调用。
体现这句话的代码,我在源码中没有找到,于是我在测试类的main方法中加入以下代码:
if(proxyinstanceofProxy){
InvocationHandlerinvocationHandler=Proxy.getInvocationHandler(proxy);
invocationHandler.invoke(proxy,realObject.getClass().getMethod("getMyName"),null);System.out.println("--------------------------------------");}
这段代码的输出结果如下,与上述中调用代理对象中的getMyName方法输出是一样的,不知道Jvm底层是否是这样判断的:
dynamicproxyhandlerconstuctor:classcom.huhx.proxy.RealObject
dynamicproxyname:classcom.sun.proxy.$Proxy0
method:getMyName
args:nullmynameishuhxinvokeobjectisnull--------------------------------------
友情链接
- 测试动态代理的源代码下载访问密码7d08
本文内容总结:动态代理的简要说明,一、InvocationHandler(interface)的描述:,二、Proxy(Class)的描述:,简单的Java代理,一、先定义一个接口Interface,添加两个方法。,二、定义一个真实的实现上述接口的类,RealObject:,三、定义一个代理对象,也实现了上述的Interface接口:,四、SimpleMain在Main方法中,测试上述的结果:,五、运行的结果如下:,Java的动态代理,一、创建一个继承了InvocationHandler的处理器:DynamicProxyHandler,二、我们写一个测试的Main方法,DynamicProxyMain:,三、运行结果如下:,Java动态代理的原理,一、动态代理的关键代码就是Proxy.newProxyInstance(classLoader,interfaces,handler),我们跟进源代码看看:,二、我们看一下newInstance方法的源代码:,三、当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的invoke方法来进行调用。,友情链接,
原文链接:https://www.cnblogs.com/huhx/p/dynamicTheoryAdvance.html