Java动态代理的理解
2018-08-23 09:08
483 查看
代码内容:
Subject接口
packagecom.advance.dynamic_proxy; /** *Createdbyhaseeon2018/8/22. */ publicinterfaceSubject { publicvoidrent(); publicvoidhello(Stringstr); }
RealSubjec类t实现Subject
packagecom.advance.dynamic_proxy;/** *Createdbyhaseeon2018/8/22. */ /** *@Auther:谷天乐 *@Date:2018/8/2219:35 *@Description: */ publicclassRealSubjectimplementsSubject { @Override publicvoidrent() { System.out.println("Iwanttorentmyhouse"); } @Override publicvoidhello(Stringstr) { System.out.println("hello:"+str); } }
DynamicProxy实现InvocationHandler,必须要实现InvocationHandler类
packagecom.advance.dynamic_proxy;/** *Createdbyhaseeon2018/8/22. */ importjava.lang.reflect.InvocationHandler; importjava.lang.reflect.Method; /** *@Auther:谷天乐 *@Date:2018/8/2219:36 *@Description: */ publicclassDynamicProxyimplementsInvocationHandler { // 这个就是我们要代理的真实对象 privateObjectsubject; //构造方法,给我们要代理的真实对象赋初值 publicDynamicProxy(Objectsubject) { this.subject=subject; } @Override publicObjectinvoke(Objectobject,Methodmethod,Object[]args) throwsThrowable { // 在代理真实对象前我们可以添加一些自己的操作 System.out.println("beforerenthouse"); System.out.println("Method:"+method); //当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用 method.invoke(subject,args); // 在代理真实对象后我们也可以添加一些自己的操作 System.out.println("afterrenthouse"); returnnull; } }
启动类
packagecom.advance.dynamic_proxy;/** *Createdbyhaseeon2018/8/22. */ importjava.lang.reflect.InvocationHandler; importjava.lang.reflect.Proxy; /** *@Auther:谷天乐 *@Date:2018/8/2219:36 *@Description: */ publicclassClient { publicstaticvoidmain(String[]args) { //我们要代理的真实对象 SubjectrealSubject=newRealSubject(); //我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的 InvocationHandlerhandler=newDynamicProxy(realSubject); /* *通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数 *第一个参数handler.getClass().getClassLoader(),我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象 *第二个参数realSubject.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了 *第三个参数handler,我们这里将这个代理对象关联到了上方的InvocationHandler这个对象上 */ Subjectsubject=(Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(),realSubject .getClass().getInterfaces(),handler); System.out.println(subject.getClass().getName()); subject.rent(); subject.hello("world"); } }
原理:
通过代理类关联到InvocationHandler中的invoke方法调用了真实对象的方法,而不是直接调用的我们可以对代理的方法前后自由的增加操作
先看InvocationHandler是什么东西
/** *{@codeInvocationHandler}istheinterfaceimplementedby *the<i>invocationhandler</i>ofaproxyinstance. *InvocationHandler是一个被代理实例的调用程序实现的接口 *<p>Eachproxyinstancehasanassociatedinvocationhandler. *Whenamethodisinvokedonaproxyinstance,themethod *invocationisencodedanddispatchedtothe{@codeinvoke} *methodofitsinvocationhandler. *每个代理实例都有相关联的调用处理程序 当一个方法被代理实例调用时,调用方法会被编码并分派它的调用程序的调用方法 *@authorPeterJones *@seeProxy *@since1.3 */
再看InvocationHandler中唯一一个方法invoke
/** *Processesamethodinvocationonaproxyinstanceandreturns *theresult.Thismethodwillbeinvokedonaninvocationhandler *whenamethodisinvokedonaproxyinstancethatitis *associatedwith. * *@paramproxytheproxyinstancethatthemethodwasinvokedon *参数proxy是指方法被调用的代理实例 *@parammethodthe{@codeMethod}instancecorrespondingto *theinterfacemethodinvokedontheproxyinstance.Thedeclaring *classofthe{@codeMethod}objectwillbetheinterfacethat *themethodwasdeclaredin,whichmaybeasuperinterfaceofthe *proxyinterfacethattheproxyclassinheritsthemethodthrough. *参数method是一个实例,它就是调用在代理实例上的接口方法。声明的 方法对象类是该方法声明的接口,这个接口是所有继承当前method的代理接口的父接口 *@paramargsanarrayofobjectscontainingthevaluesofthe *argumentspassedinthemethodinvocationontheproxyinstance, *or{@codenull}ifinterfacemethodtakesnoarguments. *Argumentsofprimitivetypesarewrappedininstancesofthe *appropriateprimitivewrapperclass,suchas *{@codejava.lang.Integer}or{@codejava.lang.Boolean}. *参数args是包含了代理方法调用中传输的对象数组参数。 或者这个接口没有参数。 原始类型的参数被打包在合适的包装类中,如Integer或者Boolean 意思就是int会包装成Integer... */
publicObjectinvoke(Objectproxy,Methodmethod,Object[]args) throwsThrowable;
我们真正执行rent()和hello(Stringstr)方法的地方在DynamicProxy类中
//当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
method.invoke(subject,args);
声明一个真实对象,InvocationHandler引用子类(在C++中接口实际就是一个父类,所以我这么说)传入真实对象
//我们要代理的真实对象
SubjectrealSubject=newRealSubject();
//我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
InvocationHandlerhandler=newDynamicProxy(realSubject);
Proxy的newProxyInstance()方法
*@paramloadertheclassloadertodefinetheproxyclass
loader是加载类类加载定义代理类
*@paraminterfacesthelistofinterfacesfortheproxyclass
*toimplement
interfaces是代理类实现的interface的集合
*@paramhtheinvocationhandlertodispatchmethodinvocationsto
h是一个handler用来分派方法去调用
@CallerSensitive
publicstaticObjectnewProxyInstance(ClassLoaderloader,
Class<?>[]interfaces,
InvocationHandlerh)
throwsIllegalArgumentException
{
Objects.requireNonNull(h);
//在这里对我们的接口进行了复制
finalClass<?>[]intfs=interfaces.clone();
finalSecurityManagersm=System.getSecurityManager();
if(sm!=null){
checkProxyAccess(Reflection.getCallerClass(),loader,intfs);
}
/*
*Lookuporgeneratethedesignatedproxyclass.
*/
Class<?>cl=getProxyClass0(loader,intfs);
/*
*Invokeitsconstructorwiththedesignatedinvocationhandler.
*/
try{
if(sm!=null){
checkNewProxyPermission(Reflection.getCallerClass(),cl);
}
finalConstructor<?>cons=cl.getConstructor(constructorParams);
finalInvocationHandlerih=h;
if(!Modifier.isPublic(cl.getModifiers())){
AccessController.doPrivileged(newPrivilegedAction<Void>(){
publicVoidrun(){
cons.setAccessible(true);
returnnull;
}
});
}
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);
}
}
控制台输出结果
第一个结果com.sun.proxy.$Proxy0是System.out.println(subject.getClass().getName());
可以清晰地看到,我们用到了代理类,而不是自己定义的Subject类
com.sun.proxy.$Proxy0
beforerenthouse
Method:publicabstractvoidcom.advance.dynamic_proxy.Subject.rent()
Iwanttorentmyhouse
afterrenthouse
beforerenthouse
Method:publicabstractvoidcom.advance.dynamic_proxy.Subject.hello(java.lang.String)
hello:world
afterrenthouse
总结:
代理是通过代理类关联到InvocationHandler中的invoke方法调用了真实对象的方法,从而完成了代理过程相关文章推荐
- 彻底理解JAVA动态代理
- Java动态代理的理解(知乎转发)
- Java之深入理解JDK动态代理
- 轻松理解Java动态代理
- java动态代理Proxy类的理解
- Java动态代理的自己理解
- 十分钟理解Java中的动态代理
- 理解Java动态代理(1)—找我还钱?我出钱要你的命
- 彻底理解JAVA动态代理
- 好记性不如烂笔头46-java拦截器-彻底理解动态代理的概念(1)
- 对于java动态代理模式的深入理解
- 理解java动态代理
- 彻底理解JAVA动态代理
- 深入源码理解-java动态代理
- JAVA动态代理的理解
- 彻底理解JAVA动态代理
- 彻底理解Java动态代理
- java动态代理--比较容易理解的例子
- 彻底理解JAVA动态代理
- Java 动态代理机制简单理解