代理模式
定义:
为其他对象提供一种代理以控制对这个对象的访问
类图:
- Proxy:代理对象。实现与具体的目标对象一样的接口,这样可以随机使用代理来代替具体的目标对象;保存一个指向具体目标对象的引用,可以在需要的时候调用具体的目标对象;还可以控制对具体目标对象的访问,并可以负责创建和删除它
- Subject:目标接口。声明代理和具体目标对象的共同接口,这样就可以在任何使用真实目标对象的地方使用代理对象。客户端通常需要针对目标接口编程
- RealSubject:具体目标对象。真正实现目标接口要求的功能
实现代码:
/** *抽象的目标接口 *@Author: April *@Date: 2015年2月24日 */ public interface Subject { public void request(); } /** * 具体的目标对象 */ public class RealSubject implements Subject{ @Override public void request() { System.out.println("具体的功能处理"); } } /** * 代理类 */ public class Proxy implements Subject{ //持有被代理的目标对象 private Subject subject = null; public Proxy(Subject subject) { this.subject = subject; } @Override public void request() { //在调用具体目标对象前,执行的操作... subject.request(); //在调用具体目标对象后,执行的操作... } }
java的动态代理
静态代理与动态代理
静态代理(Static Proxy)中,代理类和委托类都是事先存在的,代理类所实现的接口和所代理的方法都被固定,如果需要为不同的委托类提供代理类或者代理一个委托类中的不同方法,都需要增加新的代理类。而动态代理(Dynamic Proxy)就是一种可以让系统能够根据实际需要来动态创建代理类的机制。
这里讲的很清楚(先看这里)
IBM Java技术文档库: java动态代理机制分析及扩展
事务的模拟实现
有这样一个保存数据库的操作
通过动态代理为其加入事务控制,模拟java.lang.reflect.Proxy代理类类似于:public interface TaskService { public void save(); } public class Task implements TaskService{ @Override public void save() { System.out.println("保存数据库操作..."); } }
模拟事务的调用处理器/** * 假设所有的被代理对象都实现了某个接口,针对这个接口生成代理 * @date 2013-9-13 */ public class Proxy { /** * @param infac : 代理对象接口 * @param h : 调用处理器接口 */ public static Object newProxyInstance(Class<?> infac,InvocationHandler h) throws Exception{ /***********************##接口中方法的源码##***********************/ StringBuffer methodStr = new StringBuffer(); Method[] method=infac.getMethods(); for(Method m:method){ methodStr.append(" @Override \r\n"); methodStr.append(" public void "+m.getName()+"() { \r\n"); methodStr.append(" Method md; \r\n"); methodStr.append(" try{ \r\n"); methodStr.append(" md="+infac.getName()+".class.getMethod(\""+m.getName()+"\");\r\n"); methodStr.append(" h.invoke(this,md,null); \r\n"); methodStr.append(" }catch(Exception e){ \r\n"); methodStr.append(" e.printStackTrace(); \r\n"); methodStr.append(" }catch(Throwable e){ \r\n"); methodStr.append(" e.printStackTrace(); \r\n"); methodStr.append(" } \r\n"); methodStr.append(" } \r\n"); } /***********************##总源码##***********************/ StringBuffer codeStr = new StringBuffer(); codeStr.append("package com.april.pattern.proxyDynamic; \r\n"); codeStr.append("import java.lang.reflect.InvocationHandler; \r\n"); codeStr.append("import java.lang.reflect.Method; \r\n"); codeStr.append("public class $Proxy1 implements "+infac.getName()+"{\r\n"); codeStr.append(" InvocationHandler h; \r\n"); codeStr.append(" public $Proxy1(InvocationHandler h) { \r\n"); codeStr.append(" super(); \r\n"); codeStr.append(" this.h=h; \r\n"); codeStr.append(" } \r\n"); codeStr.append( methodStr); codeStr.append("} \r\n"); //得到当前项目的根路径 D:\eclipse\workspace\Proxy String path=System.getProperty("user.dir"); //得到文件目录 String fileName=path+"/src/com/april/pattern/proxyDynamic/$Proxy1.java"; //输出到文件中 File f =new File(fileName); FileWriter fw=new FileWriter(f); fw.write(codeStr.toString()); fw.flush(); fw.close(); /***********************##编译##***********************/ //获取到Java编译器,即javac JavaCompiler compiler=ToolProvider.getSystemJavaCompiler(); //System.out.println(compiler.getClass().getName());//com.sun.tools.javac.api.JavacTool //获取fileMgr 这个fileMgr管理着动态生成的文件 编译 StandardJavaFileManager fileMgr=compiler.getStandardFileManager(null, null, null); Iterable<? extends JavaFileObject> 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:/"+System.getProperty("user.dir")+"/src")}; URLClassLoader ul=new URLClassLoader(urls); Class<?> c=ul.loadClass("com.april.pattern.proxyDynamic.$Proxy1"); //生成新对象 Constructor<?> ctr=c.getConstructor(InvocationHandler.class);//获取参数为InvocationHandler类型的构造方法 Object o= ctr.newInstance(h); return o; } }
客户端import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * 事务的调用处理器 * @date 2015-2-28 */ public class TransactionHandler implements InvocationHandler{ Object target;//被代理对象 public TransactionHandler(Object target) { super(); this.target = target; } /** * 核心方法,集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问 * @param proxy :代理类实例 * @param method :被调用的方法对象 * @param args :调用参数 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{ long start = 0; long end = 0; try { start =System.currentTimeMillis(); System.out.println("开启事务 : "+start); method.invoke(target); end =System.currentTimeMillis(); System.out.println("关闭事务 : "+end); } catch (Exception e) { end =System.currentTimeMillis(); System.out.println("回滚事务 : "+end); e.printStackTrace(); } System.out.println("运行时间 : "+(end-start));//获取方法运行时间 return null; } }
动态代理生成的代理类具体是什么样的呢?public class Client { public static void main(String[] args) { Task task = new Task(); InvocationHandler h=new TransactionHandler(task); TaskService proxyTask = null; try { proxyTask = (TaskService) Proxy.newProxyInstance(TaskService.class, h); proxyTask.save(); } catch (Exception e) { e.printStackTrace(); } } } /*~output: 开启事务 : 1425263395105 保存数据库操作... 关闭事务 : 1425263395105 运行时间 : 0 */
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class $Proxy1 implements com.april.pattern.proxyDynamic.TaskService{ InvocationHandler h; public $Proxy1(InvocationHandler h) { super(); this.h=h; } @Override public void save() { Method md; try{ md=com.april.pattern.proxyDynamic.TaskService.class.getMethod("save"); h.invoke(this,md,null); //最终由调用处理器实现对委托类的代理访问 }catch(Exception e){ e.printStackTrace(); }catch(Throwable e){ e.printStackTrace(); } } }