深度模拟java动态代理实现机制系类之三
这里的内容就比较复杂了,要实现的是对任意的接口,对任意指定的方法,以及对任意指定的代理类型进行代理,就更真实的模拟出java虚拟机的动态代理机制
罗列一下这里涉及的类、接口之间的关系,方便大家学习。
1、InvocationHandler接口,用来处理指定的方法,即对特定方法的代理,处理的具体实现交由子类实现
2、TimeHandler类,实现了InvocationHandler接口的子类,具体的代理实现是进行时间代理
3、Proxy类,用于产生代理类的类
4、Moveable接口,举例过程中各类要实现的统一接口
5、Tank类,实现了Moveable接口,即被代理的类
6、Cilent,操作客户端
先把整个的思路理一下:
首先在Client端,new一个被代理的对象Tank,Tank对象作为构造参数传入代理处理类TimeHandler,new出一个TimeHandler对象,
Tank的接口Moveable和TimeHandler对象作为参数传入Proxy,Proxy调用newProxyInstance方法,该方法中对接口的所有的方法,利用TimeHandler对象进行代理,(可以简单理解为将接口方法与TimeHandler代理方法结合),生成新的代理对象的java文件、class文件、然后加载进入内存,利用反射获得一个代理对象,返回该代理对象,在Client端调用则调用了代理对象方法;
1、InvocationHandler接口
package com.csu.proxy; import java.lang.reflect.Method;
//对任意方法自定义处理
//方法调用的处理器
public interface InvocationHandler { //定义一个接口,用来处理方法,处理的具体实现交由子类实现 public void invoke(Object o, Method m); //对某个指定方法的处理
}
2、TimeHandler类
package com.csu.proxy; import java.lang.reflect.Method;
public class TimeHandler implements InvocationHandler {
private Object target;//被代理的对象 public Object getT() {
return target;
} public void setT(Object t) {
this.target = t;
} public TimeHandler(Object target) {
this.target = target;
} @Override
public void invoke(Object o,Method m){ //必须指定具体对象对具体的方法的调用
long start = System.currentTimeMillis();
System.out.println("start time is " + start);
System.out.println(o.getClass().getName());
//m 调用方法
try {
m.invoke(target);
} catch (Exception e) {e.printStackTrace();} long end = System.currentTimeMillis();
System.out.println("end time is "+end);
System.out.println("time is "+(end - start));
}
}
3、Moveable接口
package com.csu.proxy;
public interface Moveable {
void move();
}
4、Tank类
package com.csu.proxy;
import java.util.Random;
public class Tank implements Moveable {
@Override
public void move() {
System.out.println("Tank Moving...");
try {
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
5、Proxy类
package com.csu.proxy; import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader; /**
方便大家阅读,关注主要的逻辑思路,将在前面博客的已经写过的注释代码清除,因为这是一系列,有很多代码引用
有想要看的,去上几篇文章看吧
**/ //该类要实现对任意接口,任意方法,以及任意的代理 的实现
public class ProxyG3 {
public static Object newProxyInstance(Class intf, InvocationHandler h) throws Exception{
//invocationHandler当成参数,指定代理的类型,即指定对方法要进行什么处理 //*****************1、获得java文件**********************************
String methodsString = "";
String rt = "\r\n"; Method[] methods = intf.getMethods();
for(Method m : methods) {
methodsString += "@Override" + rt +
"public void " + m.getName() + "() {" + rt +
" try {" + rt +
" Method md = " + intf.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt +
" h.invoke(this, md);" + rt +
" }catch(Exception e) {e.printStackTrace();}" + rt + "}";
} String src =
"package com.csu.proxy;" + rt +
"import java.lang.reflect.Method;" + rt +
"public class TankTimeProxy implements " + intf.getName() + "{" + rt +
" public TankTimeProxy(InvocationHandler h) {" + rt +
" this.h = h;" + rt +
" }" + rt + " com.csu.proxy.InvocationHandler h;" + rt + methodsString +
"}";
String fileName = "g:/src/com/csu/proxy/TankTimeProxy.java";//放在指定的地方
File f = new File(fileName);
FileWriter fw = new FileWriter(f);
fw.write(src);
fw.flush();
fw.close();
/**
这里重点说一下:用于存放代理对象TankTimeProxy的java和class文件的包名要工程中的其他java文件的包名一致,查看代码你会发现
工程的java文件和生成的代理对象的java文件的包名都是 com.csu.proxy;
**/ //****************2、获得class文件**************************************** //获得编译器对象
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); //管理动态生成的文件
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null,null,null);
Iterable units = fileManager.getJavaFileObjects(fileName); //“编译任务”对象
JavaCompiler.CompilationTask task = compiler.getTask(null,fileManager,null,null,null,units);
task.call();
fileManager.close(); //*****************3、加载至内存****************************************** //通过Url引入本地文件
URL[] urls = new URL[]{new URL("file:/"+"g:/src/")}; //访问本地文件 指定class文件存放的位置
URLClassLoader urlClassLoader = new URLClassLoader(urls);
Class c = urlClassLoader.loadClass("com.csu.proxy.TankTimeProxy"); //******************4、执行class文件,返回代理对象*************************************** //获得构造方法
Constructor constructor = c.getConstructor(InvocationHandler.class); //getConstructor的参数为Class类型,是原构造方法的参数的Class类型 //产生新对象
Object m = constructor.newInstance(h); return m;
}
} 6、Cilent客户端 package com.csu.proxy; public class Client {
public static void main(String[] args) throws Exception { Tank t = new Tank();
InvocationHandler h = new TimeHandler(t); Moveable m =(Moveable) ProxyG3.newProxyInstance(Moveable.class, h); m.move(); }
}
7、执行结果
(1)生成的java和class文件

(2)查看生成的java文件代码

(3)运行结果

深度模拟java动态代理实现机制系类之三的更多相关文章
- 深度模拟java动态代理实现机制系类之一
上一篇博客是最基本的动态代理原理的实现,因为其固定了接口,固定了代理方法,以及固定了代理的类型,接下来的博客系类将一步步渐入深度介绍java的动态代理的实现原理 ******************* ...
- 深度模拟java动态代理实现机制系类之二
这次我们要实现的是对任意接口,任意的方法进行特定的代理 这里不一样的只有Proxy类,要实现对所有方法进行代理,那么重点就在于获得接口的所有方法 import java.io.File; import ...
- 透过字节码生成审视Java动态代理运作机制
对于动态代理我想应该大家都不陌生,就是可以动态去代理实现某个接口的类来干一些我们自己想要的功能,但是在字节码层面它的表现是如何的呢?既然目前刚好在研究字节码相关的东东,有必要对其从字节码角度来审视一下 ...
- Java 动态代理机制分析及扩展
Java 动态代理机制分析及扩展,第 1 部分 王 忠平, 软件工程师, IBM 何 平, 软件工程师, IBM 简介: 本文通过分析 Java 动态代理的机制和特点,解读动态代理类的源代码,并且模拟 ...
- [转]Java 动态代理机制分析及扩展
引言 Java 动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类.代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执 ...
- Java 动态代理机制分析及扩展--转
http://www.ibm.com/developerworks/cn/java/j-lo-proxy1/#icomments http://www.ibm.com/developerworks/c ...
- Java 动态代理机制分析及扩展,第 1 部分
Java 动态代理机制分析及扩展,第 1 部分 http://www.ibm.com/developerworks/cn/java/j-lo-proxy1/ 本文通过分析 Java 动态代理的机制和特 ...
- JAVA动态代理的全面深层理解
Java 动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类.代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执行的过 ...
- 一文读懂Java动态代理
作者 :潘潘 日期 :2020-11-22 事实上,对于很多Java编程人员来说,可能只需要达到从入门到上手的编程水准,就能很好的完成大部分研发工作.除非自己强主动获取,或者工作倒逼你学习,否则我们好 ...
随机推荐
- QNX 实时操作系统(Quick Unix)
Gordon Bell和Dan Dodge在1980年成立了Quantum Software Systems公司,他们根据大学时代的一些设想写出了一个能在IBM PC上运行的名叫QUNIX(Quick ...
- Linux 下五个顶级的开源命令行 Shell
这个世界上有两种 Linux 用户:敢于冒险的和态度谨慎的. 其中一类用户总是本能的去尝试任何能够戳中其痛点的新选择.他们尝试过不计其数的窗口管理器.系统发行版和几乎所有能找到的桌面插件. 另一类用户 ...
- ORM框架-VB/C#.Net实体代码生成工具(EntitysCodeGenerate)【ECG】4.5
摘要:VB/C#.Net实体代码生成工具(EntitysCodeGenerate)[ECG]是一款专门为.Net数据库程序开发量身定做的(ORM框架)代码生成工具,所生成的程序代码基于OO.ADO.N ...
- Java再学习——CopyOnWrite容器
一,定义 CopyOnWrite容器即写时复制的容器.通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完 ...
- LOG4J.PROPERTIES配置详解(转载)
Log4J的配置文件(Configuration File)就是用来设置记录器的级别.存放器和布局的,它可接key=value格式的设置或xml格式的设置信息.通过配置,可以创建出Log4J的运行环境 ...
- [Arduino] Leonardo 中文介绍
以下内容均翻译自arduino.cc,水平有限,如有错误请大家指正. 概述Arduino Leonardo是基于ATmega32u4一个微控制器板.它有20个数字输入/输出引脚(其中7个可用于PWM输 ...
- [转]poll技术
poll()函数:这个函数是某些Unix系统提供的用于执行与select()函数同等功能的函数,下面是这个函数的声明: #include <poll.h> int poll(struct ...
- Android学习笔记⑧——UI组件的学习AdapterView相关2
前面都是用ListView控件来配合Adapter做的一些实例,这次我们来见识一下GridView与Adapter之间的爱恨情仇.... GridView是用于在界面上按行.列分布的方式来显示多个的组 ...
- Ios入门
storyboard 文件的认识 用来描述软件界面 默认情况下程序启动就会加载Main.storyboard 加载storyboard时,会首先创建和显示箭头所指向的控制器界面 什么是UIscroll ...
- iOS 6编程Cookbook(影印版)
<iOS 6编程Cookbook(影印版)> 基本信息 原书名:iOS 6 Programming Cookbook 作者: Vandad Nahavandipoor 出版社:东南大学出版 ...