注册本站  论坛  繁體中文

电脑技巧
手机 | MP3 | MP4 | 显卡 | 主板 | 显示器 | 光存储 | 笔记本 | 网络设备 | 移动存储 | 数码相机
键鼠 | CPU | 音箱 | GPS | 电视 | 服务器 | 投影机 | 机箱电源 | 品牌电脑 | 办公打印 |
| 网站首页 | Cisco | Windows | Linux | Java | Dotnet | Oracle | 网页设计 | 平面设计 | 安全 | 软件应用 | 电脑维修 | 办公维修 |
您现在的位置: 电脑技巧 >> Java >> 核心技术 >> 高级编程 >> Java正文

使用Java Annotations来管理对象生命周期

文章来源:中国IT实验室收集整理 作者:佚名 更新时间:2008-6-28 20:32:21 【 】 【加入收藏

      对于开发者来说,复杂的应用通常有很多初始化问题需要处理。许多不同的步骤无非是建立面板,配置服务之类。而这些事情的难点在于,有一些步骤需要重复,另一些则不需要。把这种管理问题交给类自己处理是非常麻烦的,因为逻辑可能会变化。另外,现代软件设计强调分离职责。简单来说,我们的目的是把做什么和怎么做分离开来。

      Annotations

      Annotations是J2SE 5.0引入的新语言特性。通常, Annotations允许开发者用一种跟运行代码无关的次要信息来标注类,方法以及成员。这样就可以使用类似评价的 Annotations,比如“好方法”、“坏方法”,或者更详细一些,“不推荐的方法”、“覆写的方法”。这些用法的可能性是无穷的。不过请注意,方法或类跟标注实际可能不相关,比如“不推荐的”。如果想知道关于 Annotations的更多详细讨论,请阅读Java 5.0 Tiger: A Developer's Notebook。

      因为 Annotations可以用来描述用例或者实体比如方法和类的意思,所以这是一种语法棒棒糖。反过来,这些附加信息也可以被其他东西(比如框架)用于各种各样的动作,比如生成文档(Javadoc),或者像这里讨论的,作为一种特殊内容来控制行为,比如对象的生命周期。

      生命周期管理

      生命周期管理通常发生在中间件环境中,比如应用服务器。这种思想是把对象的创建、使用以及销毁跟对象本身分开。例如在一个发布不同服务的应用服务器中,它通常不关心所请求的特殊服务(译注:此处的意思应该是应用服务器对所有请求都一视同仁),调用服务的机制或多或少的采用了同一种方案。这取决于应用的状态,呼叫者以及其他参数,一些必要的变量,但是在一个易于管理的环境中,基本的算法通常是一系列操作的顺序链。在Java客户端应用中,必须处理mask的显示,或者form允许用户输入或修改数据。

      示例问题

      在Java应用中,mask通常用于数据收集以及在CRUD(create, read, update, delete)周期中处理数据。用户可以修改、删除或者新增加一些数据。跟一个简单的商务问题一样,我们需要管理在客户端应用中如何显示mask。这样,我们把显示从操作链中分离了出来,像下面这样:

      1.创建:mask在这一状态中最好只安排一次。

      2.初始化:在这一状态,数据从文件和数据库等地方找回,并填充到mask的字段中。

      3.激活:这里,用户放弃对mask的控制。

      在现实中,涉及到很多方面:访问、验证、控制依赖等等。

      Phases

      在这篇讨论中,我提到了每一步操作的phase,基本思想非常简单:我们把类方法标注成操作链中的phases,然后把这些方法的调用交给服务(框架)来做。实际上,这种方法并不仅限于生命周期管理。它可以用做商务流程中所有调用的控制机制。

      我们使用的 Annotations简单的命名为Phase,我们使用它来把一个方法标注成操作链的一部分。在下面的代码里,你可以看到 Annotations的声明与接口很接近。

      @Retention(RetentionPolicy.RUNTIME)

      @Target({ElementType.METHOD})

      public @interface Phase {

      int index();

      String displayName() default "";}

      我们简单看一下代码。在头两行,你看到 Annotations跟另外两个 Annotations一起使用。刚看上去时,这有点混乱,但是这两行很简单的就指定了 AnnotationsPhase只允许并且应该保留到编译后。之所以增加这两个 Annotations,是因为有些 Annotations可能只会在编译期间被使用,并且可能指向类或者成员。

      @interface是一个 Annotations的标准描述。在接下来的代码中,index和displayName??不只声明了一个成员,还声明了一个方法??也是Java的新语法。如果没提供初始值的话, displayName将被赋予了一个空字符串作为初始值,同时这个displayName能够被用来作为监测用途,叫做progress bar. index()是必须的,它告诉框架这些phase可以被缺省的执行。

      像我早先说的那样,我们应该把这个逻辑从对象中分离出来,所以我们定义了一个必须实现的接口以用于调用管理。这个接口可以被一个客户端对象实现。为了达到管理的目的,我们定义了一个通用的标记接口,所有的“phaseable”接口必须从这里继承,这样框架就可以通过一个唯一的访问点来管理类。

      public interface Phased {}

      这个接口的具体实现会看起来像下面的代码那样。这里,接口定义了一个mask,或者一个form,它们包含几个操作,这些操作必须像上面的描述那样被定义。

             public interface PhasedMask extends Phased {
      @Phase(index=0)

      public void construct();

      @Phase(index=1)

      public void initialize();

      @Phase(index=2,displayName="Activating...")

      public void activate();}

      你可以看到如何使用 Annotations。它写在方法声明之前,并使用一个介绍性的@sign,它的属性index需要提供圆括号。请注意,因为 Annotations并不是一个Java声明,所以结尾不能出现分号。现在,我们需要一个类来来把这些东西联结起来,并且试试我们刚才定义的phase。

      Phaser

      主要处理类也许应该被称为Phaser。(喂,我们不都挺喜欢星际旅行吗?)它执行全部的phase,并且为用户提供简单的监视机制。这个类的实现并不包含在这篇文章里,当然,你可以从资源找到框架代码的下载。

      一个Phaser拥有一个实现了一些具体的PhasedXxxx接口并且管理phase调用的对象。

      假设我们有一个像这样的MyMask类:

      

 

          public class MyMask implements PhasedMask {
      @Phase(index = 0)

      public void construct() {

      // Do the layout }

      @Phase(index = 1)

      public void initialize() {

      // Fill the mask with data }

      @Phase(index = 2)

      public void activate() {

      // Activate the listeners and allow the user to interact with the mask }

      // Business code}

 

     现在,我们可以像下面那样调用这些PhasedMask方法:
      Phaser phaser = new Phaser( phasedMask );phaser.invokeAll();

      这样,方法construct()、initialize()和activate()就都被调用了。

      那么我们如何控制phase呢?我们跳过构造阶段,因为当我们第二次调用phasedMask()时,并不需要再布置一次。本意是我们不需要construct()被调用多次。因为我们把这个方法用0索引标注,所以我们可以简单的跳过这个索引,并且告诉Phaser应该执行哪些phase。

      Phaser phaser = new Phaser( phasedMask );phaser.invoke( new int[] {1,2} );

      这样就好了,不过不够清晰。谁会记得phase的索引实际代表什么?幸运的是,我们可以像下面这样写得详细一点:

      Phaser phaser = new Phaser( phasedMask );

      phaser.invoke( new String[] {"initialize","activate"} );

      这里,我们使用从接口继承来的方法名。当然,如果需要的话,我们可以重新安排phase。所以,为了交换顺序,我们可以这样写:

      Phaser phaser = new Phaser( phasedMask );

      phaser.invoke( new String[] {"activate","initialize"} );

      这个好象没什么意义,但是,当某个设置中一些phase是紧耦合的时,这种做法是有用的。

      因为我们在这里通过反射来调用方法,所以存在很多抛出异常的情况。Phaser会捕捉这些异常,并包装成所谓的PhaserException。所以,如果一个方法调用失败(比如是私有的),Phaser的invoke()方法会抛出一个包含着最初异常的PhaseException。如果对反射知之不多,请看边栏的“Notes on Reflection”。

      你也许会给Phaser增加一个PhaseListener来观察里面发生了什么,并在漫长的phase调用过程中反馈给用户一些信息。

             PhaseListener listener = new PhaseListener() {
      public void before( PhaseEvent e ) {

      // This is called before the Phaser invokes a phase }

      public void after( PhaseEvent e ) {

      // This is called after the Phaser has successfully invoked a phase }

      }; Phaser phaser = new Phaser( phasedMask );phaser.addPhaseListener( listener );

      phaser.invoke( new String[] {"initialize","activate"} );

      讨论和总结

      在这篇文章中,你看到了如何利用 Annotations来管理被分成几个phase的类的生存周期。为了使这些类能够被框架组件所管理,它们必须简单的实现一个接口,这个接口从Phased派生而来,并且用Phase Annotations标注了方法。管理通过Phaser类来完成,这个类能够调用被标注方法,并能控制调用的顺序,还提供了一种事件处理机制来观察Phaser的工作。

      这种方法也显示了一种比Javadoc的 Annotations使用更进一步的用法。它们不只用于生命周期管理,也可以用于常规的对象初始化。

      实现类不关心它们的方法被调用的顺序。如果你在设计中保持这种思想,你就可以更灵活的使用这些类。

      如果phase必须重新排列或者忽略,这些行为会发生在实现类中。

      像任何工具一样,它有一些缺点。如果接口必须改变,或者新接口必须保持向后兼容性以保证源代码完全可用,那么实现类必须改变。这种方案缺少参数和返回值的支持。参数必须在phase调用前被完全提供。同样,因为大量使用了反射,所以会成为一个高性能要求的系统中的瓶颈。

      最后,调用链对IDE来说是不明晰的。

  • 上一篇Java:

  • 下一篇Java:
  • 最 新 热 门
     手机开发平台指南、教程和资料介绍
     关于什么叫面向接口编程
     编写高级JavaScript应用代码
     不要验证,直接转化科学计数法
     Eclipse插件开发中实现刷新和重编译介绍
     Java开源技术:Eclipse的使用技巧详解
     配置eclipse 3.2 使用JDK1.5中文JavaAPI
     集成Windows本地应用到Eclipse RCP 程序中
     hibernate.cfg.xml配置文件的说明
     eclipse开发jface时,main.class解决方法
    最 新 推 荐
     JSP高访问量下的计数程序
     得到两个日期之间的间隔天数
     Java的“静态库链接”
     用Java的加密机制来保护你的数据
     使用Java Annotations来管理对象生命周期
     JAVA实现的AZDG加密-解密算法
     基于RSA模型转换框架的开发
     如何重构出DAO模式
     关于AOP的应用实例
     关于数字排列的一个程序
    相 关 文 章

    编写高级JavaScript应用代码
    Java开源技术:Eclipse的使用技巧详解
    配置eclipse 3.2 使用JDK1.5中文JavaAPI
    Java WebService 整理笔记
    使用异步Bean提高Web服务性能
    深入探索 高效的Java异常处理框架
    J2ME中使用低级界面实现简单数字输入
    怎样减小JAR文件大小
    妙用异步Servlet扩展AJAX应用程序
    java.servlet.Filter的应用

    | 设为首页 | 加入收藏 | 联系站长 | 友情链接 | 版权申明 | 网站公告

     

    Copyright 2006-2008 pcjx.com All Rights Reserved
    电脑技巧 版权所有 粤ICP备06059145号 地图
    本网站所有内容未经许可不得转载或做其他使用