代理模式与动态代理

代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。这种情况原因很多,比如需要创建一个开销很大的对象,或者被调用的对象在远程主机上,或者目标对象的功能还不足以满足需求。


代理模式一般涉及到的角色有
–抽象角色:声明真实对象和代理对象的共同接口(可以看成租房子一件事)
–代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装(可以看成中介)
–真实角色:代理角色所代表的真实对象,是我们最终要引用的对象(可以看成房主)



静态代理

真实对象已经存在,代理类能够直接访问到真实对象。

例如下面一个操作。一个接口Image,一个实现类BigImage,它的构造函数是一个比较耗时的操作,一个代理类ProxyImage,它持有对BigImage的引用,并进行了相对应的方法增强。


(1) 抽象角色

 

  1. public interface Image  
  2. {  
  3.     public void show();  
  4. }  


(2) 真实角色

 

  1. public class BigImage implements Image  
  2. {  
  3.     public  BigImage()   
  4.     {  
  5.         //模拟一个比较耗时的初始化工作  
  6.         try  
  7.         {  
  8.             Thread.sleep(3000);  
  9.         }  
  10.         catch (InterruptedException e)  
  11.         {  
  12.             // TODO Auto-generated catch block  
  13.             e.printStackTrace();  
  14.         }  
  15.     }  
  16.   
  17.     @Override  
  18.     public void show()  
  19.     {  
  20.         System.out.println("BigImage show method");  
  21.           
  22.     }  
  23.   
  24. }  


(3) 代理角色,定义了两个方法对真实事件进行增强

 

  1. public class ProxyImage implements Image  
  2. {  
  3.     private BigImage bigImage;//真实的对象  
  4.   
  5.     @Override  
  6.     public void show()  
  7.     {  
  8.         if(bigImage==null)  
  9.         {  
  10.             bigImage=new BigImage();//首先持有一个真实对象  
  11.         }  
  12.         preMethod(); //代理事件前增强  
  13.         bigImage.show();//真实对象的方法  
  14.         postMethod();//代理事件后增强  
  15.   
  16.     }  
  17.     private void preMethod()  
  18.     {  
  19.         System.out.println("preMethod");  
  20.     }  
  21.     private void postMethod()  
  22.     {  
  23.         System.out.println("postMethod");  
  24.     }  
  25.   
  26. }  


(4) 测试代码

 

  1. public static void main(String[] args)  
  2.     {  
  3.         System.out.println(System.currentTimeMillis());//开始事件  
  4.         Image image=new ProxyImage();  
  5.         System.out.println(System.currentTimeMillis());//结束时间  
  6.         image.show();  
  7.         System.out.println(System.currentTimeMillis());  
  8.     }  


测试代码很简单,使用代理对象代替了真实对象,完成了同样的事情,并且可以在原方法前后加入增强的方法。这里面分别显示了初始化的时候,开始时间以及结束时间,可以看到耗时为0。那么这种代理到底有什么用呢?

(1)这种方式把比较耗时的操作推迟到了真正需要它的时候才创建,这样能保证前面程序运行的流畅性,而且能够减少BigImage在系统中存活时间,从宏观上节省了系统开销;

(2)在有些情况下,也许程序永远不会真正调用show()方法,这就意味着系统无需创建BigImage对象。在这种情况下,可以显著地提高系统的运行性能。hibernate延迟加载所采用的设计模式。当实体A B之间存在关联关系时,当系统加载A的时候,B并没有被加载出来,A实体里持有的B的引用全部是代理对象,只有等到A真正去访问B的时候,系统才会从数据库里去抓取B实体对应的记录。


Java的动态代理去解决。


动态代理


java中动态代理主要依靠InvocationHandler这个接口以及Proxy这个类的方法来实现。

动态代理是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。

InvocationHandler 接口

 

public interface InvocationHandler
Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.

 


invoke方法

Objectinvoke(Object proxy,Method method, Object[] args) 

 

在CODE上查看代码片派生到我的代码片
  1. public interface Subject  
  2. {  
  3.     public void something();  
  4.   
  5. }  


(2)真实对象

 

  1. public class RealSubject implements Subject  
  2. {  
  3.   
  4.     @Override  
  5.     public void something()  
  6.     {  
  7.         System.out.println("realSubject do something");  
  8.     }  
  9.   
  10. }  


(3) 动态代理类  动态动态类需要实现InvokeHandler接口,在这个示例里,对真实对象的方法进行了增强

 

  1. public class DynmaticProxy implements InvocationHandler  
  2. {  
  3.   
  4.     private Object target;  
  5.     public DynmaticProxy(Object target)  
  6.     {  
  7.         this.target=target;  
  8.     }  
  9.     @Override  
  10.     public Object invoke(Object proxy, Method method, Object[] args)  
  11.             throws Throwable  
  12.     {  
  13.         System.out.println("before事务增强。。。");  
  14.         Object result=method.invoke(target, args);  
  15.         System.out.println("after 事务增强。。。。");  
  16.         return result;  
  17.     }  
  18.   
  19. }  


(4) 测试用例


 

  1. public static void main(String[] args)  
  2.     {  
  3.         Subject subject=new RealSubject();  
  4.           
  5.         InvocationHandler invocationHandler=new DynmaticProxy(subject);  
  6.           
  7.         //生成代理对象  
  8.           
  9.         Subject subjectProxy=(Subject)Proxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(), invocationHandler);  
  10.         subjectProxy.something();  
  11.           
  12.     }  


这种动态代理在AOP里被称为AOP代理,AOP代理可以代替目标对象,AOP代理包含了目标对象的全部方法,并且AOP代理里的方法可以在执行目标方法之前、之后插入一些通用的方法。当Spring容器中的Bean实现了一个或多个接口时,Spring所创建的AOP代理就是这种动态代理。而且Spring的动态代理更加灵活,在定义InvocationHandler的时候invoke方法时,它并没有使用硬编码的方式决定调用那些拦截器,而是通过配置文件来决定invoke()方法中使用哪些拦截器,这就实现了更彻底的解耦。


posted @ 2017-01-04 22:08  hnist_hd  阅读(169)  评论(0编辑  收藏  举报