分享

Java动态代理学习2

 hh3755 2014-12-02

一、代理模式


代理模式是常用的java设计模式,特征是代理类委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。

代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。  

按照代理的创建时期,代理类可以分为两种:

静态代理:由程序员创建或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。 
动态代理:在程序运行时运用反射机制动态创建而成。

 

二、静态代理

 

  1. public interface CountDao  
  2. {  
  3.     // 查看账户方法  
  4.     public void queryCount();  
  5.  
  6.     // 修改账户方法  
  7.     public void updateCount();  
  8.  
  9. }  
  10.  
  11. public class CountDaoImpl implements CountDao  
  12. {  
  13.     public void queryCount()  
  14.     {  
  15.         System.out.println("查看账户方法...");  
  16.     }  
  17.  
  18.     public void updateCount()  
  19.     {  
  20.         System.out.println("修改账户方法...");  
  21.     }  
  22. }  
  23.  
  24. public class CountProxy implements CountDao  
  25. {  
  26.     private CountDao countDao;  
  27.  
  28.     public CountProxy(CountDao countDao)  
  29.     {  
  30.         this.countDao = countDao;  
  31.     }  
  32.  
  33.     @Override 
  34.     public void queryCount()  
  35.     {  
  36.         System.out.println("事务处理之前");  
  37.         countDao.queryCount();  
  38.         System.out.println("事务处理之后");  
  39.     }  
  40.  
  41.     @Override 
  42.     public void updateCount()  
  43.     {  
  44.         System.out.println("事务处理之前");  
  45.         countDao.updateCount();  
  46.         System.out.println("事务处理之后");  
  47.     }  
  48. }  
  49.  
  50. public class TestCount  
  51. {  
  52.     public static void main(String[] args)  
  53.     {  
  54.         CountProxy countProxy = new CountProxy(new CountDaoImpl());  
  55.         countProxy.updateCount();  
  56.         countProxy.queryCount();  
  57.     }  
  58. }  

观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且所有的代理操作除了调用的方法不一样之外其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。 


 

三、动态代理

与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。

 

1 JDK动态代理

JDK动态代理中包含一个类和一个接口

InvocationHandler接口

 

  1. public interface InvocationHandler {   
  2.     public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;   
  3. }   

Object proxy:指被代理的对象。
Method method:要调用的方法
Object[] args:方法调用时所需要的参数

可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject

 

Proxy类

Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法:

  1. public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,   
  2. InvocationHandler h) throws IllegalArgumentException  

ClassLoader loader:类加载器
Class<?>[] interfaces:得到全部的接口
InvocationHandler h:得到InvocationHandler接口的子类实例

  1. public interface PersonService  
  2. {  
  3.     public void save();  
  4. }  
  5.  
  6. public class PersonServiceImpl implements PersonService  
  7. {  
  8.     public void save()  
  9.     {  
  10.         System.out.println("人员增加");  
  11.     }  
  12. }  
  13.  
  14. import java.lang.reflect.InvocationHandler;  
  15. import java.lang.reflect.Method;  
  16. import java.lang.reflect.Proxy;  
  17.  
  18. public class PersonProxy implements InvocationHandler  
  19. {  
  20.     // 目标对象  
  21.     private Object target;  
  22.  
  23.     // 返回一个代理类对象  
  24.     public Object createProxyInstance(Object target)  
  25.     {  
  26.         this.target = target;  
  27.         return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);  
  28.     }  
  29.  
  30.     // 上述代码中调用的this就是当前代理对象,会自动调用该方法  
  31.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable  
  32.     {  
  33.         Object result = null;  
  34.         System.out.println("前置通知");  
  35.         try 
  36.         {     
  37.             result = method.invoke(target, args);  
  38.             System.out.println("后置通知");  
  39.         }  
  40.         catch(Exception e)  
  41.         {  
  42.             System.out.println("例外通知——出错啦");  
  43.         }  
  44.         finally 
  45.         {  
  46.             System.out.println("最终通知——结束啦");   
  47.         }  
  48.         return result;  
  49.     }  
  50. }  
  51.  
  52. public class TestProxy  
  53. {  
  54.     public static void main(String[] args)  
  55.     {  
  56.         PersonProxy bp = new PersonProxy();  
  57.         PersonService ps = (PersonService)bp.createProxyInstance(new PersonServiceImpl());  
  58.         ps.save();  
  59.     }  

前置通知
人员增加
后置通知
最终通知——结束啦

JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这就要使用cglib动态代理了。 

 

2 CGLIB动态代理

JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承所以不能对final修饰的类进行代理。

  1. public interface PersonService  
  2. {  
  3.     public void save();  
  4. }  
  5.  
  6. public class PersonServiceImpl implements PersonService  
  7. {  
  8.     public void save()  
  9.     {  
  10.         System.out.println("人员增加");  
  11.     }  
  12. }  
  13.  
  14. import java.lang.reflect.InvocationHandler;  
  15. import java.lang.reflect.Method;  
  16. import java.lang.reflect.Proxy;  
  17.  
  18. /**  
  19.  * 使用CGLIB动态代理  
  20.  */ 
  21. public class PersonProxy implements MethodInterceptor  
  22. {  
  23.     private Object target;  
  24.  
  25.     // 返回一个代理类对象  
  26.     public Object createProxyInstance(Object target)  
  27.     {  
  28.         this.target = target;  
  29.         Enhancer enhancer = new Enhancer();  
  30.  
  31.         // 设置目标类为父类,会覆盖目标类的非final方法  
  32.         enhancer.setSuperclass(this.target.getClass());  
  33.  
  34.         // 回调方法  
  35.         enhancer.setCallback(this);  
  36.  
  37.         // 创建代理对象  
  38.         return enhancer.create();  
  39.     }  
  40.  
  41.     // 上述代码中调用的this就是当前代理对象,会自动调用该方法  
  42.     // 方法一  
  43.     @Override 
  44.     public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable  
  45.     {  
  46.         Object result = null;  
  47.         System.out.println("前置通知");  
  48.         try 
  49.         { 
  50.             result = method.invoke(target, args);  
  51.             System.out.println("后置通知");  
  52.         }  
  53.         catch (Exception e)  
  54.         {  
  55.             System.out.println("例外通知——出错啦");  
  56.         }  
  57.         finally 
  58.         {  
  59.             System.out.println("最终通知——结束啦");  
  60.         }  
  61.         return result;  
  62.     }  
  63. }  
  64.  
  65. public class PersonProxy2 implements MethodInterceptor  
  66. {  
  67.     private Object target;  
  68.  
  69.     // 返回一个代理类对象  
  70.     public Object createProxyInstance(Object target)  
  71.     {  
  72.         this.target = target;  
  73.         Enhancer enhancer = new Enhancer();  
  74.  
  75.         // 设置目标类为父类,会覆盖目标类的非final方法  
  76.         enhancer.setSuperclass(this.target.getClass());  
  77.  
  78.         // 回调方法  
  79.         enhancer.setCallback(this);  
  80.  
  81.         // 创建代理对象  
  82.         return enhancer.create();  
  83.     }  
  84.       
  85.     // 方法二  
  86.     public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable  
  87.     {  
  88.         Object result = null;  
  89.         System.out.println("前置通知");  
  90.         try 
  91.         {   
  92.             result = proxy.invokeSuper(obj, args);  
  93.             System.out.println("后置通知");  
  94.         }  
  95.         catch (Exception e)  
  96.         {  
  97.             System.out.println("例外通知——出错啦");  
  98.         }  
  99.         finally 
  100.         {  
  101.             System.out.println("最终通知——结束啦");    
  102.         }  
  103.         return result;  
  104.     }  
  105. }  
  106.  
  107. public class TestProxy  
  108. {  
  109.     public static void main(String[] args)  
  110.     {  
  111.         PersonProxy cglib = new PersonProxy();  
  112.         PersonServiceClass ps1 = (PersonServiceClass) cglib.createProxyInstance(new PersonServiceClass());  
  113.         ps1.save();  
  114.         System.out.println("--------------------");  
  115.         PersonProxy2 cglib2 = new PersonProxy2();  
  116.         PersonServiceClass ps2 = (PersonServiceClass) cglib2.createProxyInstance(new PersonServiceClass());  
  117.         ps2.save();  
  118.     }  

前置通知
增加人员
后置通知
最终通知——结束啦
--------------------
前置通知
增加人员
后置通知
最终通知——结束啦
 

参考并演绎自地址:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html

本文出自 “IT徐胖子的专栏” 博客,请务必保留此出处http://woshixy.blog.51cto.com/5637578/1066208

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

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多