Java注释和apt(基础)

Eug*_*gie 5 java annotations

我真的卷起袖子,试图第一次理解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.
    }
}

唉,我的问题!

  1. 我假设我需要定义一个注释处理器; 一个Java类,它将指定在遇到@Widgetize(int)注释时要执行的操作,是吗?或者这种情况发生在比如获取apt的 XML配置文件中(就像ant读取build.xml文件的方式)?

  2. 编辑:如果我对上面问题#1中的这些注释处理器是正确的,那么我如何"映射"/"注册"/将这些处理器告知apt?

  3. 在buildscripts中,apt通常 javac 之前运行,因此在编译之前进行基于注释的更改或代码生成?(这是一个最佳实践类型的问题).

谢谢,我为我的代码示例道歉,结果比我想要的更笨重(!)

Pac*_*ace 5

这听起来更像是AOP(面向方面​​的编程)而不是注释。由于 AOP 使用注释来实现其目标,因此这些主题经常令人困惑。我建议查找现有的 AOP 库,例如AspectJ ,而不是从头开始重新发明 AOP 。

但是,为了回答您的具体问题,有两种可能的方法可以实现您的目标。

运行时方法

这是容器框架(如 Spring)通常采用的方法。它的工作方式是,您不需要自己实例化您的类,而是向容器请求您的类的实例。

容器具有检查类中任何 RuntimeAnnotations(如 @Widgetize)的逻辑。然后,容器将动态创建您的类的代理,该代理首先调用正确的 Widgetize 方法,然后调用目标方法。

然后,容器将该代理返回给原始请求者。请求者仍然认为他得到了他所请求的类(或接口),并且完全不知道容器添加的代理行为。

这也是 AspectJ 使用的行为。

强化方法

这就是 AspectJ 所采取的方法。说实话,我不太了解它是如何工作的很多细节。不知何故,AspectJ 将扫描您的类文件(字节代码),找出注释在哪里,然后修改字节代码本身以调用代理类而不是实际的类。

这种方法的好处是您不需要使用容器。缺点是您现在必须在编译代码后执行此增强步骤。