[转]动态代理机制初探

转载 2012年03月21日 10:14:44

本文出处:http://www.blogjava.net/sitinspring/archive/2008/05/28/203359.html



动态代理机制初探

功能代码的多余枝节

当我们书写执行一个功能的函数时,经常需要在其中写入与功能不是直接相关但很有必要的代码,如日志记录,信息发送,安全和事务支持等,以下代码是一个用户注册类的代码:

/**
 * 用於用戶注冊的服務類
 * 
@author: sitinspring(junglesong@gmail.com)
 * @date: 2008-5-27-下午09:15:25
 
*/

public class RegisterService{
  
/**
   * 注冊一個用戶
   * 
@param name 用戶名
   * 
@param pswd 用戶密碼
   * 
@param email 用戶郵件地址
   
*/

  
public void register(String name,String pswd,String email){
    Logger.log(
"將注冊一個新用戶"+name);
    
    
// 真正的,应该由本函數擔負的處理
    System.out.println("存儲用戶信息到數據庫");
    
    MailSender.send(email, 
"歡迎"+name+"注冊為本系統的用戶");
  }

}


Logger类代码

/**
 * 模擬記錄器
 * 
@author: sitinspring(junglesong@gmail.com)
 * @date: 2008-5-27-下午09:17:56
 
*/

public class Logger{
  
/**
   * 模擬記錄信息到文件中
   * 
@param str
   
*/

  
public static void log(String str){
    System.out.println(getCurrTime()
+"INFO:"+str);
  }

  
  
/**
   * 取得當前時間
   * 
@return
   
*/

  
private static String getCurrTime() {
    Date date 
= new Date();
    Format formatter 
= new SimpleDateFormat("HH时mm分ss秒");
    
return formatter.format(date);
  }

}


MailSender类代码

/**
 * 模擬郵件發送器
 * 
@author: sitinspring(junglesong@gmail.com)
 * @date: 2008-5-27-下午09:23:31
 
*/

public class MailSender{
  
/**
   * 模擬發送郵件
   * 
@param title
   * 
@param msg
   
*/

  
public static void send(String email,String concept){
    System.out.println(
""+email+"發送郵件 內容為:"+concept+"的郵件");
  }

}



枝节性代码给功能性代码带来的麻烦

诸如日志记录,信息发送,安全和事务支持等枝节代码虽然是必要的,但它会带来以下麻烦:
1.枝节性代码游离在功能性代码之外,它们不是函数的目的,这对OO是一种破坏。
2.枝节性代码会造成功能性代码对其它类的依赖,加深类之间的耦合度,而这是OO系统所竭力避免的。
3.枝节性代码带来的耦合度会造成功能性代码移植困难,可重用性降低。
4.从法理上说,枝节性代码应该“监视”着功能性代码,然后采取行动;而不是由功能性代码“通知”枝节性代码采取行动。这好比吟游诗人应该是主动记述骑士的功绩而不是骑士主动要求诗人记录自己的功绩的。

如何两种代码分离开来

毫无疑问,枝节性代码和功能性代码(主干性代码)需要分离开来才能降低耦合程度,符合现代OO系统的要求,而java提供的动态代理机制可以帮助我们实现这一点。
动态代理机制主要的类是java.lang.reflect.Proxy,它从一诞生就受到了重视,并在RMI,EJB和AOP中都得到广泛的应用,其重要程度唯有反射能与之相比。

Proxy代理模式

在讲述动态代理之前我们可以回顾一下代理模式,它的定义是这样的:代理可以提供对另一个对象的访问,同时隐藏实际对象的具体事实。代理一般会实现它所表示的实际对象的接口。代理可以访问实际对象,但是延迟实现实际对象的部分功能,实际对象实现系统的实际功能,代理对象对客户隐藏了实际对象。客户不知道它是与代理打交道还是与实际对象打交道。
如果我们使用代理模式,把枝节性代码放入代理类中,这样主干性代码保持在真实的类中,这样不就能有效降低耦合度吗?这种通过在耦合紧密的类之间引入一个中间类是降低类之间的耦合度的常见做法。
具体来说就是把枝节性代码放入代理类中,它们由代理类负责调用,而真实类只负责主干的核心业务,它也由代理类调用,它并不知道枝节性代码的存在和作用,因为这本不是它的任务。对外来说,代理类隐藏在接口之后,客户并不清楚也不需要清楚具体的调用过程。通过这样的处理,主干与枝节之间的交叉解开了,外界的调用也没有复杂化,这就有效降低系统各部分间的耦合度。
下面让我们先看看代码

消除了枝节代码的注册类

/**
 * 用於用戶注冊的服務類
 * 
@author: sitinspring(junglesong@gmail.com)
 * @date: 2008-5-27-下午09:15:25
 
*/

public class RegisterService implements IService{
  
/**
   * 注冊一個用戶
   * 
@param name 用戶名
   * 
@param pswd 用戶密碼
   * 
@param email 用戶郵件地址
   
*/

  
public void register(String name,String pswd,String email){
    
// 真正的,該由本函數擔負的處理
    System.out.println("存儲用戶信息到數據庫");
  }

}



注册类的代理类,枝节性代码都被转移到了这里

/**
 * 注冊服務代理類
 * 
@author: sitinspring(junglesong@gmail.com)
 * @date: 2008-5-27-下午09:45:10
 
*/

public class RegisterServiceProxy implements InvocationHandler {
  
// 代理對象
    Object obj;
    
    
// 構造函數,傳入代理對象
    public RegisterServiceProxy(Object o) {
        obj 
= o;
    }


    
/**
     * 调用被代理对象的将要被执行的方法,我们可以在调用之前進行日誌記錄,之后执行郵件發送
     
*/

    
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
        Object result 
= null;
        
try {
          
// 進行日誌記錄
            String name=(String)args[0];
          Logger.log(
"將注冊一個新用戶"+name);

          
// 調用Object的方法
            result = m.invoke(obj, args);
            
            
// 执行郵件發送
            String email=(String)args[2];
            MailSender.send(email, 
"歡迎"+name+"注冊為本系統的用戶");
        }
 catch (InvocationTargetException e) {
        }
 catch (Exception eBj) {
        }
 finally {
            
// Do something after the method is called 
        }

        
return result;
    }

}


代理类RegisterServiceProxy的解释

该代理类的内部属性为Object类,实际使用时通过该类的构造函数RegisterServiceProxy(Object obj)对其赋值;此外,在该类还实现了invoke方法,该方法中的
method.invoke(obj,args);
其实就是调用被代理对象的将要被执行的方法,这是通过反射实现的,方法参数obj是实际的被代理对象,args为执行被代理对象相应操作所需的参数。通过动态代理类,我们可以在调用之前或者之后执行一些相关操作。

如何生成一个代理类的实例

代理类的实例需要特殊的方式生成,代码如下:

  public static IService genereteService(){
    
return (IService)Proxy.newProxyInstance(
        IService.
class.getClassLoader(),
            
new Class[]{IService.class},
            
new RegisterServiceProxy(new RegisterService()));
  }

Proxy即为java中的动态代理类,其方法Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,其中loader是类加载器,interfaces是被代理的真实类的接口,h是具体的代理类实例。

所谓动态代理是这样一种class:它是在运行时生成的类,在生成它时你必须提供一组接口给它,然后该类就宣称它实现了这些接口。你当然可以把该类的实例当作这些接口中的任何一个实现类来用。当然啦,这个动态代理类其实就是一个代理,它不会做作实质性的工作,而是在生成它的实例时你必须提供一个真实的类的实例,由它接管实际的工作。

工厂方法的作用

对于代理类生成的细节,客户(需要使用RegisterService的程序员)是没有兴趣也没有必要知道的,我们可以让它隐藏在一个工厂方法中,对外返回一个接口,这样在调用时用户就不知道他是与代理打交道还是与实际对象打交道了。使用RegisterService类时示例代码如下:

IService service=RegisterServiceFactory.genereteService();    
service.register(
"sitinspring","123456","junglesong@gmail.com");

执行完的结果和前面的代码的是一样的。

动态代理在AOP中的应用

Spring的AOP支持可以被用于从系统核心逻辑中分离交叉业务(cross-business)如日志,事务管理和安全等,使用AOP,你可以用各种功能层来覆盖核心业务层,这些功能层可以灵活的应用到你的系统中,甚至核心业务层都不知道它们的存在,这是一个强大的概念。
AOP(aspect-oriented programming)的核心就是动态代理,掌握它对于理解AOP尤为重要,犹如反射对理解IoC一样。

代码下载:
http://www.blogjava.net/Files/sitinspring/DynamicProxySample20080527235441.rar

java 动态代理机制的理解和分析

引言 Java 动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类。代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执...
  • Leonardo9029
  • Leonardo9029
  • 2016年03月28日 10:22
  • 3533

Spring AOP的实现——动态代理机制

在java的动态代理中,有两个重要的类或者接口,一个是InvocationHandler(Interface)、另一个是Proxy(Class),这一个类和接口是实现动态代理所必须的。 Invocat...
  • bingogirl
  • bingogirl
  • 2016年08月29日 21:15
  • 6871

java高级---->Java动态代理的原理

Java动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类。代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执行的过程...
  • GarfieldEr007
  • GarfieldEr007
  • 2016年12月18日 11:06
  • 376

Spring AOP中的动态代理机制

AOP:面向切面、面向方面、面向接口是一种横切技术 横切技术运用: 1.事务管理: (1)数据库事务:(2)编程事务(3)声明事物:Spring AOP-->声明事物    2.日志处理: 3...
  • linux__xu
  • linux__xu
  • 2017年08月25日 17:09
  • 164

Java代理和动态代理机制分析和应用

本博文中项目代码已开源下载地址:GitHubJava代理和动态代理机制分析和应用概述代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤...
  • fengyuzhengfan
  • fengyuzhengfan
  • 2015年12月02日 19:54
  • 3753

Mybatis源码中Mapper的动态代理实现原理

Mybatis源码中Mapper的动态代理实现原理现在工作中用的最多的就是Mybatis这款半自动ORM框架,用的久却对其了解不是很深,现在准备对其进行一些深入的学习,顺便对知识进行查漏补缺.本篇是对...
  • laixiangshun
  • laixiangshun
  • 2017年09月14日 16:26
  • 291

Spring AOP中的动态代理实现机制

AOP中的目标对象(target object),也被称为是advised object,是在pointcut处插入aspect时所执行的advice方法中所用到的对象。有点罗嗦,请慢慢体会。 任何...
  • taiyangdao
  • taiyangdao
  • 2016年04月23日 17:41
  • 433

详解java动态代理机制以及使用场景(一)

说起java动态代理,在我刚开始学java时对这项技术也是十分困惑,明明可以直接调通的对象方法为什么还要使用动态代理?随着学习的不断深入和工作经验的积累,慢慢的体会并理解了java动态代理机制。昨天再...
  • u011784767
  • u011784767
  • 2017年10月19日 10:29
  • 1021

动态代理(2)----动态代理和AOP

根据前面介绍的Proxy和InvocationHandler,实在很难看出这种动态代理的优势,下面介绍一种更实用的动态代理机制.只要我们开发一个实际使用的软件系统,总会出现相同代码重复出现的情形,在这...
  • beijiguangyong
  • beijiguangyong
  • 2013年02月28日 22:09
  • 4170

AOP的简单实现---动态代理机制

动态代理:动态代理顾名思义就是代理目标对象处理某些事情 正向代理:可以理解成火车售卖点就是中国铁路总公司的代理,我们把买票的业务委托给火车票售卖点,售卖点通过软件等形式替我们向铁总买票,然后再将...
  • yang1464657625
  • yang1464657625
  • 2016年12月20日 11:51
  • 357
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:[转]动态代理机制初探
举报原因:
原因补充:

(最多只允许输入30个字)