我真的卷起袖子,试图第一次理解Java注释,并阅读了有关该主题的Sun,Oracle和Wikipedia文章.它们在概念上很容易理解,但我发现将拼图的所有部分放在一起很困难.
以下示例可能是可怕的工程,但只是幽默我(这是一个例子!).
假设我有以下课程:
public Widget
{
// ...
public void foo(int cmd)
{
switch(cmd)
{
case 1:
function1();
break;
case 2:
function2();
break;
case 3:
default:
function3();
break;
}
}
}
现在,在我项目的其他地方,我有另一个类SpaceShuttle,它有一个名为blastOff()的方法:
public class SpaceShuttle
{
// ...
public void blastOff()
{
// ...
}
}
那么现在,我想配置称为注释Widgetize使之与注释的任何方法@Widgetize将之前自己的呼叫的Widget :: foo的(INT)调用.
@interface Widgetize
{
int cmd() default 2;
}
那么现在让我们重新审视SpaceShuttle:
public class SpaceShuttle
{
// ...
@Widgetize(3)
public void blastOff()
{
// Since we pass a cmd of "3" to @Widgetize,
// Widget::function3() should be invoked, per
// Widget::foo()'s definition.
}
}
唉,我的问题!
我假设我需要定义一个注释处理器; 一个Java类,它将指定在遇到@Widgetize(int)注释时要执行的操作,是吗?或者这种情况发生在比如获取apt的 XML配置文件中(就像ant读取build.xml文件的方式)?
编辑:如果我对上面问题#1中的这些注释处理器是正确的,那么我如何"映射"/"注册"/将这些处理器告知apt?
在buildscripts中,apt通常在 javac 之前运行,因此在编译之前进行基于注释的更改或代码生成?(这是一个最佳实践类型的问题).
谢谢,我为我的代码示例道歉,结果比我想要的更笨重(!)
这听起来更像是AOP(面向方面的编程)而不是注释。由于 AOP 使用注释来实现其目标,因此这些主题经常令人困惑。我建议查找现有的 AOP 库,例如AspectJ ,而不是从头开始重新发明 AOP 。
但是,为了回答您的具体问题,有两种可能的方法可以实现您的目标。
运行时方法
这是容器框架(如 Spring)通常采用的方法。它的工作方式是,您不需要自己实例化您的类,而是向容器请求您的类的实例。
容器具有检查类中任何 RuntimeAnnotations(如 @Widgetize)的逻辑。然后,容器将动态创建您的类的代理,该代理首先调用正确的 Widgetize 方法,然后调用目标方法。
然后,容器将该代理返回给原始请求者。请求者仍然认为他得到了他所请求的类(或接口),并且完全不知道容器添加的代理行为。
这也是 AspectJ 使用的行为。
强化方法
这就是 AspectJ 所采取的方法。说实话,我不太了解它是如何工作的很多细节。不知何故,AspectJ 将扫描您的类文件(字节代码),找出注释在哪里,然后修改字节代码本身以调用代理类而不是实际的类。
这种方法的好处是您不需要使用容器。缺点是您现在必须在编译代码后执行此增强步骤。