分享

java 代理模式实现:java原生proxy类和增强型cglib库

 hmtomyang 2012-03-29

大家可能都听说过spring的AOP编程,其实用java的反射机制也可以轻松实现。

我对AOP一个浅显的理解就是,当你在调用某个方法时,可以在调用之前或调用之后执行一些预前操作或预后操作,而不用更改被调用方法把预前操作或预后操作硬编码进去,你可以采用一种更灵活的方式,就是用代理模式来实现。

 

场景介绍:当我们在吃水果的时候,我们并不是直接拿到水果就吃,而是1.先用水洗洗水果,再2.吃水果,3.吃完后再洗洗手,擦擦嘴

操作2是我们直接想做的事,而操作1和操作3则是预前和预后操作。

 

怎么做呢?

 

用组合方法简单实现代理模式

实现1:

 

抽象一个Person接口,定义一个Person的实现类PersonA,再实现代理类

 

输出结果:

 

washing:apple

person A is eating:apple

washing hands

 

 

 

用java原生java.lang.reflect.Proxy实现

 

实现2只适应于特定接口的代理,如果我们想实现对任何接口的代理呢。

为什么现在只提到接口呢,可能你会问,为什么不直接对具体类进行代理呢?问的好,因为java.lang.reflect.Proxy类只能对接口进行代理,对具体类的代理要放到最后才讲,所以为了由浅入深,先卖个关子。君莫急。

 

实现2:

 

 

输出结果:

 

washing:apple

person A is eating:apple

washing hands

 

 

 

 

封装实现2

有人可能会觉得,我还得再写一个handler,再调用proxy.newInstance.好麻烦啊,能不能一次性搞定。好,给你。

虽然代理的是具体类,但需要具体类实现某个接口。但已经能模拟直接代理具体类了。

如这里虽然直接代理PersonA,但还是需要Person接口。等到了实现4就可以去掉Person接口了。

我还加了点东西,至于是什么,你看看就知道了。


实现3

  1. public class ProxyBroker implements InvocationHandler {  
  2.     private Object delegate = null;  
  3.     private ProxyBroker(Object delegate) {  
  4.         // TODO Auto-generated constructor stub  
  5.         this.delegate = delegate;  
  6.     }  
  7.     public static Object newProxy(Object obj) {  
  8.         ProxyBroker broker = new ProxyBroker(obj);  
  9.         Class[] interfaces = obj.getClass().getInterfaces();  
  10.         Class inteface = null;  
  11.         if (Pattern  
  12.                 .compile("^java[x]{0,1}")  
  13.                 .matcher(  
  14.                         obj.getClass()  
  15.                                 .getCanonicalName()  
  16.                                 .subSequence(  
  17.                                         0,  
  18.                                         obj.getClass().getCanonicalName()  
  19.                                                 .length())).find()) {  
  20.             if (obj.getClass().getInterfaces().length > 0)  
  21.                 inteface = obj.getClass().getInterfaces()[0];  
  22.             else  
  23.                 System.err.println("no avaliable interface implemented by :"  
  24.                         + obj.getClass().getCanonicalName());  
  25.         } else {  
  26.             for (Class interfacc : interfaces) {  
  27.                 if (!Pattern  
  28.                         .compile("^java[x]{0,1}")  
  29.                         .matcher(  
  30.                                 interfacc.getCanonicalName().subSequence(0,  
  31.                                         interfacc.getCanonicalName().length()))  
  32.                         .find()) {  
  33.                     inteface = interfacc;  
  34.                 }  
  35.             }  
  36.         }  
  37.         return Proxy.newProxyInstance(inteface.getClassLoader(),  
  38.                 new Class[] { inteface }, broker);  
  39.     }  
  40.     @Override  
  41.     public Object invoke(Object proxy, Method method, Object[] args)  
  42.             throws Throwable {  
  43.         // TODO Auto-generated method stub  
  44.         Object obj = null ;  
  45.         if(method.getName().equals("eat")){  
  46.         washFruit((String)args[0]) ;  
  47.          obj =  method.invoke(delegate, args);  
  48.          clean();  
  49.          }else  
  50.              obj =  method.invoke(delegate, args);  
  51.          return obj ;  
  52.            
  53.     }  
  54.     public static void main(String[] args) {  
  55.         Person p = (Person) ProxyBroker.newProxy(new PersonA());  
  56.         p.eat("apple");  
  57.         Comparable intg = (Comparable) ProxyBroker.newProxy(new Integer(10));  
  58.         System.out.println(intg.compareTo(11));  
  59.     }  
  60.       
  61.     private void washFruit(String fruit){  
  62.         System.out.println("washing:"+fruit);  
  63.     }  
  64.     private void clean(){  
  65.         System.out.println("washing hands");  
  66.     }  
  67. }  
 

 

washing:apple

person A is eating:apple

washing hands

-1 //看到这个就知道我加了什么了,我能对java.lang.Integer进行代理,但因为其实现的是Comparable<T>接口

    //所以只能调用compareTo()方法

 

 

 

cglib实现

利器出现了,不需要你想代理的类实现莫个接口,是个类就行。所以在这里,可以去掉Person接口的定义了,不要再迷恋它了。很强大的吧

 

实现4

  1. public class CglibProxyBroker implements MethodInterceptor {  
  2.     private static CglibProxyBroker delegate = new CglibProxyBroker();  
  3.       
  4.     private CglibProxyBroker() {  
  5.         // TODO Auto-generated constructor stub  
  6.     }  
  7.       public static  Object newInstance( Class clazz ){  
  8.                 try{  
  9.                       Enhancer e = new Enhancer();  
  10.                       e.setSuperclass(clazz);  
  11.                       e.setCallback(delegate);  
  12.                       return e.create();  
  13.                }catch( Throwable e ){  
  14.                    e.printStackTrace();   
  15.                   throw new Error(e.getMessage());  
  16.                }    
  17.                
  18.          }  
  19.         
  20.     @Override  
  21.     public Object intercept(Object arg0, Method arg1, Object[] arg2,  
  22.             MethodProxy arg3) throws Throwable {  
  23.         // TODO Auto-generated method stub  
  24.         Object obj  = null;  
  25.         if(arg1.getName().equals("eat")){  
  26.             washFruit((String)arg2[0]);  
  27.         obj =  arg3.invokeSuper(arg0, arg2);  
  28.         clean();  
  29.         }else  
  30.             obj = arg3.invokeSuper(arg0, arg2) ;  
  31.         return obj;  
  32.     }  
  33.       
  34.       
  35.     public static void main(String[] args) {  
  36.           
  37.         Person p = (Person)CglibProxyBroker.newInstance(new PersonA().getClass());  
  38.         p.eat("apple");  
  39.           
  40.     }  
  41.       
  42.     private void washFruit(String fruit){  
  43.         System.out.println("washing:"+fruit);  
  44.     }  
  45.     private void clean(){  
  46.         System.out.println("washing hands");  
  47.     }  
  48. }  
 

washing:apple

person A is eating:apple

washing hands

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多