一、概述

1.目标:动态代理的代理逻辑可以任意修改

2.思路:

(1)要把代理逻辑抽离,站在jvm的角度思考,应独立出InvocationHandler接口,并接收被代理的对象及方法作为参数invoke(Object o, Method m),并本身作为参数传给newProxyInstance(Class interfze,InvocationHandler handler)

(2)InvocationHandler本身聚合被代理类target,以便在target的方法前后增加代理逻辑

3.知识点:

(1)按名字找方法java.lang.reflect.Method md = proxy.Movable.class.getMethod("stop");

(2)按"."拆分字符串:String [] parts = m.toString().replace("abstract ", "").split("\\.");

二、代码

1.InvocationHandler.java

2.TimeHandler.java

3.Movable.java

4.Tank.java

5.Proxy.java

6.Client.java

1.InvocationHandler.java

 package proxy;

 import java.lang.reflect.Method;

 public interface InvocationHandler {
public void invoke(Object o, Method m);
}

2.TimeHandler.java

 package proxy;

 import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; public class TimeHandler implements InvocationHandler { //保留被代理的对象
private Object target; public TimeHandler(Object target) {
this.target = target;
} @Override
public void invoke(Object o, Method m) {
System.out.println("Time Proxy start...........");
long start = System.currentTimeMillis();
try {
//除了静态方法,方法的调用都要先已知对象,所以要把对象o作为参数传进去
m.invoke(target);
} catch (Exception e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("花费时间:"+(end - start));
System.out.println("Time Proxy end..........."); } }

3.Movable.java

 package proxy;

 public interface Movable {
public void move();
public void stop();
}

4.Tank.java

 package proxy;

 import java.util.Random;

 public class Tank implements Movable {

     @Override
public void move() {
System.out.println("Tank moving.......");
try {
Thread.sleep(new Random().nextInt(2000));
} catch (InterruptedException e) {
e.printStackTrace();
}
} @Override
public void stop() {
System.out.println("Tank stopping......."); } }

5.Proxy.java

 package proxy;

 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; import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider; public class Proxy { public static Object newProxyInstance(Class interfze,InvocationHandler handler) throws Exception { String rt = "\n\r"; //拼接"实现接口方法"的字符串
String methodStr = "";
for(Method m: interfze.getMethods() ){ //取出方法的修饰符和返回值类型
String [] parts = m.toString().replace("abstract ", "").split("\\.");
String [] parts2 = parts[0].split(" "); methodStr +=
"@Override" + rt +
parts2[0]+" "+parts2[1]+" "+m.getName()+"() {" + rt +
"try{"+ rt +
"java.lang.reflect.Method md = " + interfze.getName() + ".class.getMethod(\""+m.getName()+"\");" + rt +
//传this进去其实没什么用,invoke实际是调用target的方法m.invoke(target)
"handler.invoke(this, md);" + rt +
"}catch(Exception e){"+ rt +
" e.printStackTrace();" + rt +
"}" + rt + "}"+ rt ;
} //动态代理文件的源码
String str =
"package proxy;" + rt + "public class TankTimeProxy implements " + interfze.getName() + " {"+rt+ //聚合Handler
"private InvocationHandler handler;" + rt + "public TankTimeProxy(InvocationHandler handler) {" + rt +
"this.handler = handler;" + rt +
"}" + rt + methodStr + rt + "}" ; //把源码写到java文件里
File file = new File(System.getProperty("user.dir")+"/src/proxy/TankTimeProxy.java");
FileWriter fw = new FileWriter(file);
fw.write(str);
fw.flush();
fw.close(); //编译源码,生成class,注意编译环境要换成jdk才有compiler,单纯的jre没有compiler,会空指针错误
JavaCompiler jc = ToolProvider.getSystemJavaCompiler(); //文件管事器
StandardJavaFileManager fileMgr = jc.getStandardFileManager(null, null, null); //编译单元
Iterable units = fileMgr.getJavaFileObjects(file); //编译任务
CompilationTask t = jc.getTask(null, fileMgr, null, null, null, units); //编译
t.call();
fileMgr.close(); //把类load到内存里
URL[] urls = new URL[] {new URL("file:/"+System.getProperty("user.dir")+"/src/proxy/TankTimeProxy.class")};
URLClassLoader uc = new URLClassLoader(urls);
Class c = uc.loadClass("proxy.TankTimeProxy"); //生成实例
//return c.newInstance(); //c.newInstance()会调用无参数的Construtor,若类没有无参的Constructor时会出错
//Constructor ctr = c.getConstructor(interfze);
Constructor ctr = c.getConstructor(InvocationHandler.class);
return ctr.newInstance(handler);
}
}

6.Client.java

 package proxy;

 import java.io.IOException;

 import org.junit.Test;

 public class Client {

     @Test
public void testProxy() throws Exception{ Movable m = (Movable)Proxy.newProxyInstance(Movable.class, new TimeHandler(new Tank()));
m.move();
m.stop(); }
}

三、运行结果

最新文章

  1. .NET跨平台:在Ubuntu上用自己编译的dnx运行ASP.NET 5示例程序
  2. 《LINUX内核设计与实现》读书笔记之第五章
  3. JS写的多级联select,如何取值
  4. JavaScript 对象 之继承对象 学习笔记
  5. JavaScript - 时间函数
  6. 几百万的数据,mysql快速高效创建索引
  7. PEAR:使用PHPDoc轻松建立你的PEAR文档
  8. 通知角标(2)只用一个TextView实现
  9. VC C运行时库(CRTL)的几个版本及选用
  10. linux reboot命令
  11. 好吧,使用sql实现Dijkstra算法
  12. js_day13
  13. 引言:Canvas绘图API快速入门
  14. 使用FSharp 探索Dotnet图像处理功能1--反色变化
  15. UEditor编辑器第一次赋值失败的解决方法
  16. 漫谈 SLAM 技术(上)
  17. R语言与数据分析之八:时间序列--霍尔特指数平滑法
  18. android studio 虚拟机adb.exe已停止工作的处理
  19. 文本框监听事件blur()的简单使用
  20. Vim的合并行操作

热门文章

  1. vs2013中把解决方案上传到SVN服务器
  2. VBS数组函数学习实例分析
  3. 最大后验估计(MAP)
  4. Hibernate 检索查询的几种方式(HQL,QBC,本地SQL,集成Spring等)
  5. android实现左右滑动菜单
  6. android下的数据存储
  7. 利用 js 实现弹出蒙板(model)功能
  8. 使用Java 8 Lambda表达式对Employee类进行操作
  9. shell grep 高亮
  10. 读书笔记:<我是一只IT小小鸟>