意图:为其他对象提供一种代理以控制对这个对象的访问。
主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上.在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层
什么时候使用:想在访问一个类时做一些控制
如何解决 :增加中间层
使用场景:按职责来划分,通常有一下使用场景:1.远程代理 2.虚拟代理 3.Copy-on-Write代理 4.保护(Protect or Access)代理 5.Cache代理 6.防火墙(Firewall)代理 7.同步化(Synchronization)代理 7.智能引用(Smart Reference)代理
注意事项:1.和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理迷失不能改变所代理类的接口 2.和装饰模式的区别:装饰模式为了增强功能,而代理模式是为了加以控制
- 模拟Proxy 类
package com.bjsxt.proxy; public interface Moveable { void move(); }
package com.bjsxt.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(); } } }
package com.bjsxt.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 infce, InvocationHandler h) throws Exception { //JDK6 Complier API, CGLib, ASM String methodStr = ""; String rt = "\r\n"; Method[] methods = infce.getMethods(); /* for(Method m : methods) { methodStr += "@Override" + rt + "public void " + m.getName() + "() {" + rt + " long start = System.currentTimeMillis();" + rt + " System.out.println(\"starttime:\" + start);" + rt + " t." + m.getName() + "();" + rt + " long end = System.currentTimeMillis();" + rt + " System.out.println(\"time:\" + (end-start));" + rt + "}"; } */ for(Method m : methods) { methodStr += "@Override" + rt + "public void " + m.getName() + "() {" + rt + " try {" + rt + " Method md = " + infce.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt + " h.invoke(this, md);" + rt + " }catch(Exception e) {e.printStackTrace();}" + rt + "}"; } String src = "package com.bjsxt.proxy;" + rt + "import java.lang.reflect.Method;" + rt + "public class $Proxy1 implements " + infce.getName() + "{" + rt + " public $Proxy1(InvocationHandler h) {" + rt + " this.h = h;" + rt + " }" + rt + " com.bjsxt.proxy.InvocationHandler h;" + rt + methodStr + "}"; String fileName = "d:/src/com/bjsxt/proxy/$Proxy1.java"; File f = new File(fileName); FileWriter fw = new FileWriter(f); fw.write(src); fw.flush(); fw.close(); //compile 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(); //load into memory and create an instance URL[] urls = new URL[] {new URL("file:/" + "d:/src/")}; URLClassLoader ul = new URLClassLoader(urls); Class c = ul.loadClass("com.bjsxt.proxy.$Proxy1"); System.out.println(c); Constructor ctr = c.getConstructor(InvocationHandler.class); Object m = ctr.newInstance(h); //m.move(); return m; } }
package com.bjsxt.proxy; import java.lang.reflect.Method; public interface InvocationHandler { public void invoke(Object o, Method m); }
package com.bjsxt.proxy; import java.lang.reflect.Method; public class TimeHandler implements InvocationHandler{ private Object target; public TimeHandler(Object target) { super(); this.target = target; } @Override public void invoke(Object o, Method m) { long start = System.currentTimeMillis(); System.out.println("starttime:" + start); System.out.println(o.getClass().getName()); try { m.invoke(target); } catch (Exception e) { e.printStackTrace(); } long end = System.currentTimeMillis(); System.out.println("time:" + (end-start)); } }
package com.bjsxt.proxy; public class Client { public static void main(String[] args) throws Exception { Tank t = new Tank(); InvocationHandler h = new TimeHandler(t); Moveable m = (Moveable)Proxy.newProxyInstance(Moveable.class, h); m.move(); } } //可以对任意的对象、任意的接口方法,实现任意的代理
- 用法示例
package com.bjsxt.proxy.test; public interface UserMgr { void addUser(); }
package com.bjsxt.proxy.test; public class UserMgrImpl implements UserMgr { @Override public void addUser() { System.out.println("1: 插入记录到user表"); System.out.println("2: 做日志在另外一张表"); } }
package com.bjsxt.proxy.test; import java.lang.reflect.Method; import com.bjsxt.proxy.InvocationHandler; public class TransactionHandler implements InvocationHandler { private Object target; public TransactionHandler(Object target) { super(); this.target = target; } @Override public void invoke(Object o, Method m) { System.out.println("Transaction Start"); try { m.invoke(target); } catch (Exception e) { e.printStackTrace(); } System.out.println("Transaction Commit"); } }
package com.bjsxt.proxy.test; import com.bjsxt.proxy.InvocationHandler; import com.bjsxt.proxy.Proxy; import com.bjsxt.proxy.TimeHandler; public class Client { public static void main(String[] args) throws Exception { UserMgr mgr = new UserMgrImpl(); InvocationHandler h = new TransactionHandler(mgr); //TimeHandler h2 = new TimeHandler(h); UserMgr u = (UserMgr)Proxy.newProxyInstance(UserMgr.class,h); u.addUser(); } }