Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 305|回复: 0

[设计模式学习]JAVA动态代理机制初探

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-11-5 00:01:59 | 显示全部楼层 |阅读模式
    功能代码的多余枝节 当我们书写执行一个功能的函数时,经常需要在其中写入与功能不是直接相关但很有必要的代码,如日志记录,信息发送,安全和事务支持等,以下代码是一个用户注册类的代码:


    /** */
    /**
      * 用於用�注�的服��
      * @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://file.javaxxz.com/2014/11/5/000158906.zip
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-25 13:46 , Processed in 0.301332 second(s), 36 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表