体验Java 1.5中面向(AOP)编程[组图](2)
现在我必须编写代码调用StatusManager的方法来报告应用程序的进程。典型情况下,这些方法调用都分散地贯穿于try-finally代码块中,通常每个方法一个调用。
public void connectToDB (String url) {
StatusManager.push("Connecting to database");
try {
...
} finally {
StatusManager.pop();
}
}
这些代码实现了我们所需要功能,但是在代码库中数十次、甚至于数百次地复制这些代码之后,它看起来就有些混乱了。此外,如果我们希望用一些其它的方式访问这些消息该怎么办呢?在本文的后面部分中,我将定义一个用户友好的异常处理程序,它共享了相同的消息。问题是我把状态消息隐藏在方法的实现之中了,而没有把消息放在消息所属的接口中。
面向属性编程
我真正想实现的操作是把对StatusManager的引用都放到代码外面的某个地方,并简单地用我们的消息标记这个方法。接着我可以使用代码生成(code-generation)或运行时反省(introspection)来执行真正的工作。XDoclet项目把这种方法归纳为面向属性编程(Attribute-Oriented Programming),它还提供了一个框架组件,可以把自定义的类似Javadoc的标记转换到源代码之中。
但是,JSR-175包含了这样的内容,Java 1.5为了包含真实代码中的这些属性提供了一种结构化程度更高的格式。这些属性被称为"注解(annotations)",我们可以使用它们为类、方法、字段或变量定义提供元数据。它们必须被显式声明,并提供一组可以包含任意常量值(包括原语、字符串、枚举和类)的名称-值对(name-value pair)。
注解(Annotations)
为了处理状态消息,我希望定义一个包含字符串值的新注解。注解的定义非常类似接口的定义,但是它用@interface关键字代替了interface,并且只支持方法(尽管它们的功能更像字段):
public @interface Status {
String value();
}
与接口类似,我把@interface放入一个叫做Status.java的文件中,并把它导入到任何需要引用它的文件中。
对我们的字段来说,value可能是个奇怪的名称。类似message的名称可能更适合;但是,value对于Java来说具有特殊的意义。它允许我们使用@Status("...")代替@Status(value="...")来定义注解,这明显更加简捷。
我现在可以使用下面的代码定义自己的方法:
@Status("Connecting to database")
public void connectToDB (String url) {
...
}
请注意,我们在编译这段代码的时候必须使用-source 1.5选项。如果你使用Ant而不是直接使用javac命令行建立应用程序,那么你需要使用Ant 1.6.1以上版本。
作为类、方法、字段和变量的补充,注解也可以用于为其它的注解提供元数据。特别地,Java引入了少量注解,你可以使用这些注解来定制你自己的注解的工作方式。我们用下面的代码重新定义自己的注解:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Status {
String value();
}
@Target注解定义了@Status注解可以引用什么内容。理想情况下,我希望标记大块的代码,但是它的选项只有方法、字段、类、本地变量、参数和其它注解。我只对代码感兴趣,因此我选择了METHOD(方法)。
@Retention注解允许我们指定Java什么时候可以自主地抛弃消息。它可能是SOURCE(在编译时抛弃)、CLASS(在类载入时抛弃)或RUNTIME(不抛弃)。我们先选择SOURCE,但是在本文后部我们会更新它。
- 上一篇:Java中基于Aspectwerkz的AOP
- 下一篇:如何迅速成为Java高手