一.理解:
代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
按照代理的创建时期,代理类可以分为两种。
静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理:在程序运行时,运用反射机制动态创建而成。
二.模拟jdk的动态代理
代码
//调用类
package com.d12321.proxy; import java.lang.reflect.Method; public class TankLogProxy implements com.d12321.proxy.movable { com.d12321.proxy.InvocationHander tank; public TankLogProxy(InvocationHander tank) { this.tank = tank; } @Override public void run() throws Exception { Method md = com.d12321.proxy.movable.class.getMethod("run"); tank.invoke(this, md); } } //运行结果 tank start .... Tank move .... tank end ....
//动态代理类Proxy(生成代理实例)
package com.d12321.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.StandardJavaFileManager; import javax.tools.ToolProvider; import javax.tools.JavaCompiler.CompilationTask; public class Proxy { public static Object newProxyInstance(Class inter, InvocationHander h) throws Exception{ String rt = "\n"; String moths= ""; Method[] ms = inter.getMethods(); /* for(Method m : ms) { moths += "@Override" +rt+ "public void " + m.getName() +"() {"+rt+ " System.out.println(\"tank start ....\");" + rt + " "+"tank."+m.getName() +"();"+ rt + " System.out.println(\"tank end ....\");" + rt + "}"; } */ for(Method m : ms) { moths += "@Override" +rt+ "public void " + m.getName() +"() throws Exception {"+rt+ " Method md = "+inter.getName()+".class.getMethod(\"" + m.getName() + "\");"+ rt+ "tank.invoke(this, md);" + rt + "}"; } String str = "package com.d12321.proxy;" + rt + rt + "import java.lang.reflect.Method;"+rt+ "public class TankLogProxy implements "+inter.getName()+" {" + rt + " com.d12321.proxy.InvocationHander tank;" + rt + " public TankLogProxy(InvocationHander tank) {" + rt + " this.tank = tank;" + rt + " }" + rt + moths + rt + " }"; //源码 String filename = System.getProperty("user.dir")+"/src/com/d12321/proxy/TankLogProxy.java"; File f = new File(filename); FileWriter fw = new FileWriter(f); fw.write(str); fw.flush(); fw.close(); //编译 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null); Iterable units = fileMgr.getJavaFileObjects(filename); CompilationTask t = compiler.getTask(null,fileMgr, null, null, null, units); t.call(); fileMgr.close(); //loader到内存 URL[] urls = new URL[] {new URL("file:/"+System.getProperty("user.dir")+"/src/")}; URLClassLoader ul = new URLClassLoader(urls); Class c = ul.loadClass("com.d12321.proxy.TankLogProxy"); //生产对象 Constructor ctr = c.getConstructor(InvocationHander.class); Object m = ctr.newInstance(h); return m; } }
//InvocationHandler接口,调用反射执行对象的方法,在方法上加上需要加上的逻辑
//接口
package com.d12321.proxy; import java.lang.reflect.Method; public interface InvocationHander { public void invoke(Object o, Method m); }
//实现接口的类
package com.d12321.proxy; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class TimeInvocationHander implements InvocationHander { private Object t; public TimeInvocationHander(Object t) { super(); this.t = t; } public Object getT() { return t; } public void setT(Object t) { this.t = t; } @Override public void invoke(Object o, Method m) { System.out.println("tank start ...."); try { m.invoke(t, new Object[]{}); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } System.out.println("tank end ...."); } }
//需要添加逻辑的类
//接口
package com.d12321.proxy; public interface movable { void run() throws Exception; //void move(); }
//类
package com.d12321.proxy; public class Tank implements movable{ @Override public void run() { System.out.println("Tank move ...."); } }
总结:
首先,Tank是实现movable接口的实例,需要添加逻辑的类,TimeInvocationHandler是实现InvocationHandler接口的实例,里面的采用Method m.invoke(Object o, , )方法调m方法,实现了向方法上添加逻辑,Proxy能够生成任意对象和添加逻辑类的实例类,就像jdk中的动态代理一样
位于java.lang.reflect.Proxy
用到的知识点
1.java的反射机制,方法如何执行
2.java如何拿到编译器,编译对象
3.java如何loader对象到内存
4.java如何生成实例对象
5.拿到当前项目的路径system.getProperty("userr.dir")