龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > 软件开发 > JAVA开发 >

Java 1.5中面向方面(AOP)编程[组图](3)

时间:2009-12-23 15:42来源:未知 作者:admin 点击:
分享到:
@Target注解定义了@Status注解可以引用什么内容。理想情况下,我希望标记大块的代码,但是它的选项只有方法、字段、类、本地变量、参数和其它注解。我

  @Target注解定义了@Status注解可以引用什么内容。理想情况下,我希望标记大块的代码,但是它的选项只有方法、字段、类、本地变量、参数和其它注解。我只对代码感兴趣,因此我选择了METHOD(方法)。
  
  @Retention注解允许我们指定Java什么时候可以自主地抛弃消息。它可能是SOURCE(在编译时抛弃)、CLASS(在类载入时抛弃)或RUNTIME(不抛弃)。我们先选择SOURCE,但是在本文后部我们会更新它。
   重构源代码

  现在我的消息都被编码放入元数据中了,我必须编写一些代码来通知状态监听程序。假设在某个时候,我继续把connectToDB方法保存源代码控件中,但是却没有对StatusManager的任何引用。但是,在编译这个类之前,我希望加入一些必要的调用。也就是说,我希望自动地插入try-finally语句和push/pop调用。

  XDoclet框架组件是一种Java源代码生成引擎,它使用了类似上述的注解,但是把它们存储在Java源代码的注释(comment)中。XDoclet生成整个Java类、配置文件或其它建立的部分的时候非常完美,但是它不支持对已有Java类的修改,而这限制了重构的有效性。作为代替,我可以使用分析工具(例如JavaCC或ANTLR,它提供了分析Java源代码的语法基础),但是这需要花费大量精力。

  看起来没有什么可以用于Java代码的源代码重构的很好的工具。这类工具可能有市场,但是你在本文的后面部分可以看到,字节码重构可能是一种更强大的技术。 重构字节码

  不是重构源代码然后编译它,而是编译原始的源代码,然后重构它所产生的字节码。这样的操作可能比源代码重构更容易,也可能更加复杂,而这依赖于需要的准确转换。字节码重构的主要优点是代码可以在运行时被修改,不需要使用编译器。

  尽管Java的字节码格式相对简单,我还是希望使用一个Java类库来执行字节码的分析和生成(这可以把我们与未来Java类文件格式的改变隔离开来)。我选择了使用Jakarta的Byte Code Engineering Library(字节码引擎类库,BCEL),但是我还可以选用CGLIB、ASM或SERP。

  由于我将使用多种不同的方式重构字节码,我将从声明重构的通用接口开始。它类似于执行基于注解重构的简单框架组件。这个框架组件基于注解,将支持类和方法的转换,因此该接口有类似下面的定义:


  public interface Instrumentor
  {
  public void instrumentClass (ClassGen classGen,Annotation a);
  public void instrumentMethod (ClassGen classGen,MethodGen methodGen,Annotation a);
  }


  ClassGen和MethodGen都是BCEL类,它们使用了Builder模式(pattern)。也就是说,它们为改变其它不可变的(immutable)对象、以及可变的和不可变的表现(representation)之间的转换提供了方法。

  现在我需要为接口编写实现,它必须用恰当的StatusManager调用更换@Status注解。前面提到,我希望把这些调用包含在try-finally代码块中。请注意,要达到这个目标,我们所使用的注解必须用@Retention(RetentionPolicy.CLASS)进行标记,它指示Java编译器在编译过程中不要抛弃注解。由于在前面我把@Status声明为@Retention(RetentionPolicy.SOURCE)的,我必须更新它。

  在这种情况下,重构字节码明显比重构源代码更复杂。其原因在于try-finally是一种仅仅存在于源代码中的概念。Java编译器把try-finally代码块转换为一系列的try-catch代码块,并在每一个返回之前插入对finally代码块的调用。因此,为了把try-finally代码块添加到已有的字节码中,我也必须执行类似的事务。

精彩图集

赞助商链接