时间:2021-05-19
为哪些方法代理?
实现自己动态代理,首先需要关注的点就是,代理对象需要为哪些方法代理? 原生JDK的动态代理的实现是往上抽象出一层接口,让目标对象和代理对象都实现这个接口,怎么把接口的信息告诉jdk原生的动态代理呢? 如下代码所示,Proxy.newProxyInstance()方法的第二个参数将接口的信息传递了进去第一个参数的传递进去一个类加载器,在jdk的底层用它对比对象是否是同一个,标准就是相同对象的类加载器是同一个
ServiceInterface) Proxy.newProxyInstance(service.getClass().getClassLoader() , new Class[]{ServiceInterface.class}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("前置通知"); method.invoke(finalService,args); System.out.println("后置通知"); return proxy; } });我们也效仿它的做法. 代码如下:
public class Test { public static void main(String[] args) { IndexDao indexDao = new IndexDao(); Dao dao =(Dao) ProxyUtil.newInstance(Dao.class,new MyInvocationHandlerImpl(indexDao)); assert dao != null; System.out.println(dao.say("changwu")); }}拿到了接口的Class对象后,通过反射就得知了接口中有哪些方法描述对象Method,获取到的所有的方法,这些方法就是我们需要增强的方法
如何将增强的逻辑动态的传递进来呢?
JDK的做法是通过InvocationHandler的第三个参数完成,他是个接口,里面只有一个抽象方法如下: 可以看到它里面有三个入参,分别是 代理对象,被代理对象的方法,被代理对象的方法的参数
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;}当我们使用jdk的动态代理时,就是通过这个重写这个钩子函数,将逻辑动态的传递进去,并且可以选择在适当的地方让目标方法执行
InvocationHandler接口必须存在必要性1:
为什么不传递进去Method,而是传递进去InvocationHandler对象呢? 很显然,我们的初衷是借助ProxyUtil工具类完成对代理对象的拼串封装,然后让这个代理对象去执行method.invoke(), 然而事与愿违,传递进来的Method对象的确可以被ProxyUtil使用,调用method.invoke(), 但是我们的代理对象不能使用它,因为代理对象在这个ProxyUtil还以一堆等待拼接字符串, ProxyUtil的作用只能是往代理对象上叠加字符串,却不能直接传递给它一个对象,所以只能传递一个对象进来,然后通过反射获取到这个对象的实例,继而有可能实现method.invoke()
InvocationHandler接口必须存在必要性2:
通过这个接口的规范,我们可以直接得知回调方法的名字就是invoke()所以说,在拼接字符串完成对代理对象的拼接时,可以直接写死它
思路
我们需要通过上面的ProxyUtil.newInstance(Dao.class,new MyInvocationHandlerImpl(indexDao))方法完成如下几件事
运行的效果:
package com.myproxy;import com.changwu.myproxy.pro.Dao;import com.changwu.myproxy.pro.MyInvocationHandler;import java.lang.reflect.Method;import java.lang.Exception;public class $Proxy implements Dao{ private MyInvocationHandler handler; public $Proxy (MyInvocationHandler handler){ this.handler =handler; } public String say(String p) { Method method = null; String [] args0 = null; Class<?> [] args1= null; try{ args0 = "java.lang.String,".split(","); args1 = new Class[args0.length]; for (int i=0;i<args0.length;i++) { args1[i]=Class.forName(args0[i]); } method = Class.forName("com.changwu.myproxy.pro.Dao").getDeclaredMethod("say",args1); }catch (Exception e){ e.printStackTrace(); } return (String) this.handler.invoke(method,"暂时不知道的方法"); }}解读
通过newInstance()用户获取到的代理对象就像上面的代理一样,这个过程是在java代码运行时生成的,但是直接看他的结果和静态代理差不错,这时用户再去调用代理对象的say(), 实际上就是在执行用户传递进去的InvocationHandeler里面的invoke方法, 但是亮点是我们把目标方法的描述对象Method同时给他传递进去了,让用户可以执行目标方法+增强的逻辑
当通过反射区执行Method对象的invoke()方法时,指定的哪个对象的当前方法呢? 这个参数其实是我们手动传递进去的代理对象代码如下
public class MyInvocationHandlerImpl implements MyInvocationHandler { private Object obj; public MyInvocationHandlerImpl(Object obj) { this.obj = obj; } @Override public Object invoke(Method method, Object[] args) { System.out.println("前置通知"); try { method.invoke(obj,args); } catch (Exception e) { e.printStackTrace(); } System.out.println("后置通知"); return null; }}作者: 赐我白日梦
出处:https:///ZhuChangwu/p/11648911.html
以上就是手动模拟JDK动态代理的方法的详细内容,更多关于模拟jdk动态代理的资料请关注其它相关文章!
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
java代理有jdk动态代理、cglib代理,这里只说下jdk动态代理,jdk动态代理主要使用的是java反射机制(既java.lang.reflect包)原理
今天来介绍另一种更为强大的代理——Cglib动态代理。 什么是Cglib动态代理? 我们先回顾一下上一篇的jdk动态代理,jdk动态代理是通过接口来在运
本文实例为大家分享了手动实现的一个简单JDK版动态代理,供大家参考,具体内容如下一.实现步骤1.根据目标类的接口类型生成代理类的java文件。2.编译代理类ja
详解javaJDK动态代理类分析(java.lang.reflect.Proxy)/***JDK动态代理类分析(java.lang.reflect.Proxy使
1.概述JDK动态代理是利用java反射机制生成一个实现接口的匿名类,在调用具体方法前调用InvocationHandler来处理Cglib动态代理是利用asm