动态代理的东东 听起来很牛,用起别人提供的现成的工具,也很方便,比如spring 的事务管理,虽然我们用的是和不是很多,但是真正用的时候,会有一些意想不到的东东出现,本着知其然并知其所以然的原则,我们来看下到底是怎么实现的
下面会研究下 java本身实现的动态代理,cglib实现的动态代理, 其他的比如bcel和javassist实现的,大家可以自己研究下,大同小异
好了,我们开始,本着诚实的原则(第二个原则) ,下面的内容错了的都是我的,对的都是自立的J。
首先看下两个实现是怎么写的,上代码(很烦,但是很必要),由于java是需要接口的,因此我们会有一个接口,同时会有实现,模拟一个简单的计时的动态代理
接口:public interface IHello { public String sayHello(String ts);}
实现:public class HelloWorld implements IHello{ public String sayHello(String ts) { return "hello "+ts; }}
Java的实现
public class DynaHello implements InvocationHandler {
private Object obj;
public DynaHello(Object obj) { this.obj = obj;}
@Override
public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
long start = System.currentTimeMillis();
Object o = method.invoke(obj, args);
System.out.println("Call to sayHello took "+ (System.currentTimeMillis() - start) + " ms.");
return o;
}
}
Cglib的实现
public class cglibProxy implements MethodInterceptor {
private Enhancer enhancer=new Enhancer();
public Object getProxyInstance(Class clz){
enhancer.setSuperclass(clz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
long start = System.currentTimeMillis();
Object o = proxy.invokeSuper(obj, args);
System.out.println("Call to sayHello took " + (System.currentTimeMillis() - start) + " ms.");
return o;
}
}
测试java 动态代理类
public class TestJavaDyna {
public static void main(String[] args) {
HelloWorld hw = new HelloWorld();
DynaHello dh = new DynaHello(hw);
IHello hello = (IHello) Proxy.newProxyInstance(hw.getClass().getClassLoader(), hw.getClass().getInterfaces(), dh);
hello.sayHello("hello world");
}
}
下面我们来看下java是怎么实现动态代理的
首先来看Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
很简单,除去异常的处理,就三句话
Class cl = getProxyClass(loader, interfaces);//@1生成一个class
Constructor cons = cl.getConstructor(constructorParams);//@2得到这个class的构造函数
return (Object) cons.newInstance(new Object[] { h });//@3用这个构造函数,和构造函数的参数 构造一个对象 然后返回
其中constructorParams ={ InvocationHandler.class }; h就是传入的InvocationHandler的实现,这里面会在生成字节码的时候,设置进去自己的父类 java/lang/reflect/Proxy,父类有一个有参构造函数比较重要
protected Proxy(InvocationHandler h) { this.h = h; } 。
下面的这幅图也许比较清晰
从上面可以看到主要还是生成代理类字节码,详细的就不讲了,举个例子讲下怎么生成对应的代理方法的,下面的就是方法生成中用到的代码
//1、这几句字节码的意思得到父类的一个属性,类型为InvocationHandler,此时superclassName = "java/lang/reflect/Proxy",handlerFieldName = "h";
out.writeByte(opc_getfield); out.writeShort(cp.getFieldRef( superclassName, handlerFieldName, "Ljava/lang/reflect/InvocationHandler;"));
//2、这句话对应的字节码就是aload_0,也就是this的引用
code_aload(0, out);
//3、这几句是得到静态属性,类型为Method,className= proxyPkg + $Proxy + num, proxyPkg是包名,因为接口的类型可以是public或者默认,public的时候proxyPkg就是空,默认的话,就需要代理类和接口在一个包内,包可见。
// num是自增计数器,methodFieldName就是代理类中的属性的name
out.writeByte(opc_getstatic); out.writeShort(cp.getFieldRef(dotToSlash(className),methodFieldName, "Ljava/lang/reflect/Method;"));
//4、下面是对应方法中的参数,如果没有则是空null
if (parameterTypes.length > 0) { code_ipush(parameterTypes.length, out);out.writeByte(opc_anewarray); out.writeShort(cp.getClass("java/lang/Object"));
for (int i = 0; i < parameterTypes.length; i++) {
out.writeByte(opc_dup);
code_ipush(i, out);
codeWrapArgument(parameterTypes[i], parameterSlot[i], out);
out.writeByte(opc_aastore);
}
} else {
out.writeByte(opc_aconst_null);
}
//5、下面两句话是调用接口,第一个参数为上面load的this,第二个参数为对应Method类型的方法,第三个参数就是上面组装的方法中的参数
out.writeByte(opc_invokeinterface);
out.writeShort(cp.getInterfaceMethodRef("java/lang/reflect/InvocationHandler","invoke","(Ljava/lang/Object;Ljava/lang/reflect/Method;" +"[Ljava/lang/Object;)Ljava/lang/Object;"))
这个太枯燥了,下面我们用jd_gui看下生成好的字节码是什么样的,挑个sayHello方法吧,除去各种异常处理,方法如下:
public final String sayHello(){ return ((String)this.h.invoke(this, m3, new Object[] { paramString })); }
其中h就是父类Proxy中的属性,m3 = Class.forName("javaDyna.IHello").getMethod("sayHello", new Class[] { Class.forName("java.lang.String") });也就是m3是接口中的方法
这个里面有个地方 sayhello没有参数了,这个是jd的问题,请大家不要纠结在这个地方。
通过这一个方法,就可以知道,java动态代理是将所有的方法都委托给了InvocationHandler实现中的invoke方法
了,
看着很简单,呵呵,但是这里面的一些异常,以及缓存的处理还是值得学些的,当然我们只看主干,就行了哈哈
上面就将生成字节码说完了,最后通过 将InvocationHandler的实现传入构造函数,就完成了代理对象的生成,
那时的h才真正是实现。
相关推荐
本文通过分析Java动态代理的机制和特点,解读动态代理类的源代码,并且模拟推演了动态代理类的可能...Java动态代理机制的出现,使得Java开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地
Java 动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类。
关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式--代理模式,而对于代理,根据创建代理类的时间点,又可以分为静态代理和动态代理。 代理模式是常用的java设计模式,他的特征是代理类与委托类有...
前言: 近一直在分析hadoop的RPC机制。...下面是动态代理的简单的代码实现,我们一起来看看吧。 代码如下: package cn.xiaolu; import java.lang.reflect.InvocationHandler; import java.lang.refle
分析了当今几种路由算法的不足和研究了移动代理优越性的基础上,提出了一种基于移动代理的动态路由协议算法的设计方案.该算法用移动代理去发现网络的短期状态,并用服务代理保存网络的长期运行状况.该文还用JAVA和IBM...
Microsoft代理服务系统的分析与实现 用Proxy+共享Internet联接 A:一般程序如何在内部网访问Internet (superboy) B:用socksonline+e-border通过http端口玩mud游戏 (superboy) C: 通过socksonline上mirc聊天...
哪怕没有看过源码的同学也应该知道,AOP是通过动态代理实现的,动态代理又分为两个部分:JDK动态代理和CGLIB动态代理 确实,Spring也就是通过这两种方式来实现AOP相关功能,下面就通过源码来简单求证下
使用非常简单,是一个可执行的jar文件, 启动以后设置一个转发端口,然后再把浏览器的代理设置为这个端口就可以了。 1. 启动以后增加一个监听端口,按下图的配置,选择Add就好了。 2. 设置浏览器的代理为 ...
数据传输系统,采用简单对象访问协议( SOAP),提供定时业务组件调用,自动数据挖掘技术和远程数据传 输、接收、汇总、分析功能。实现总部对异地分支机构的及时控制和分析。它主要通过外挂业务组件来实 现业务逻辑...
JAVA 中的代理模式介绍,课本上一般讲的比较晦涩简单,这个文档讲的比较生动易懂,很有帮助。
基于webmagic + springboot + mybatis的Java爬虫,使用Echarts进行数据可视化分析,提供了从爬虫获取数据到数据持久化、数据可视化分析以及构建简单的代理池等一整套解决方案模板。 【项目资源】: 包含前端、后端、...
是一个简单的本机HTTP代理服务器软件,使用它你可以使用HTTP代理服务器上网进行浏览,下载软件....程序还具有过滤弹出式广告窗口,代理服务器的地址和速度分析,网络带宽监测,网络浏览文件的自动清除等功能,非常容易使用!
国内服装零售终端数据分析的现状 就目前国内服装零售终端的数据分析状况看,绝大部分零售商或代理商只局限在对 年、月、周、日销售额和毛利润进行简单统计,而对数据的细微变化则关注甚少,以及 如对产品自身及消费...
提出了一个新的基于双线性对的基于身份的强代理盲签名方案,并构造了一个基于身份的多级强代理盲签名方案,实现了签名权利在许可范围内逐级向下代理的要求,并对方案的安全性和执行效率进行了分析。同时,方案也满足强...
基于代理的模拟已成功应用于建模复杂的组织行为并改善或优化组织绩效的各个方面。 提出了通过遗传算法的应用来支持智能的智能体,... 该方法不仅允许进行系统级优化,而且还提供可以分析以确定构成有效代理行为的数据。
以前写的一些分析http的demo,代码没有整理了,保持原样,大家不要介意哦:) 分析http需要一个抓包工具 本人已上传一个绿色版 ...http代理访问(呵呵,其实这个不算,就是往一个代理IP端口发http包即可)
目前在国内是下载不到glype的,因为好像对国内用户做了限制,所以这个分析给大家~Glype proxy script 是一个用 PHP 编写的基于 Web 的代理脚本,用来作为 web 的代理服务器,可帮你请求目标URL,并生成相应的页面,...
分析代码,结构很简单。。点击about运行,监听端口目前设置的是8080。。 分析了http部分,有兴趣的人可以咨询。。