【问题标题】:When the Processor code of Java Custom Annotation is called? (runtime retention)Java Custom Annotation 的处理器代码什么时候调用? (运行时保留)
【发布时间】:2021-06-28 13:47:41
【问题描述】:

我知道 Custom Java Annotations 需要一个带有 @interface 的半接口声明和一个定义实际的 processor 代码(在某些文本中称为消费者代码)注释背后的业务逻辑。到目前为止很清楚,但我的问题是,处理器代码在何处/何时被调用以及由谁调用?我的意思是,Java 编译器是否生成调用所有注释处理器的代码,例如,在类加载时?还是程序员自己决定何时为他们的自定义注释调用他们的处理器代码? 例如,@GetMapping("/users") 在某个方法上,告诉 servlet API 将请求映射到其请求路径中的 /users,应该传递给该方法。所以它在后台有一些处理器,应该调用它在某处存储此映射配置,但是何时以及谁调用该处理器?我想我的问题只对@Retention(RetentionPolicy.RUNTIME) 的注释有意义。谢谢

【问题讨论】:

  • 不需要为每个自定义注解配备注解处理器。例如,您可以简单地通过反射阅读它们。而且 servlet 不能单独运行。要运行 servlet,您需要一个框架的实现,该框架提供对 servlet 框架有意义的注释定义。所以应该清楚哪些软件处理这些注释。
  • @Holger 我并不是说我们必须为 servlet 注释等编写处理器,我知道 Spring Web 已经为注释编写了处理器。我的问题是那个处理器什么时候被调用?和谁?
  • 也许我们必须先澄清一下,您对“处理器”这个名称的理解。

标签: java annotations processor


【解决方案1】:

顾名思义,Annotation 是附加信息(或行为)。默认情况下,此信息不会被处理或用于更改任何行为。必须有一些实体来处理注释。

保留策略告诉 Java 编译器注解的范围。即是否需要在运行时或编译时处理额外的信息。

对于编译时处理,annotation processors 使用 -processor 标志挂接到编译过程。对于运行时处理,反射(例如this)用于访问附加信息。

@GetMapping("/users") 在某个方法上,告诉 servlet API 将请求映射到其请求路径中的 /users,

仅仅存在注释不会导致这种行为。 spring 框架(简化了很多)-

  • 将自身安装为/* 的servlet 端点。见FrameworkServlet
  • 使用反射枚举带有GetMapping注解的方法
  • 使用带注释的信息来填充 URL 到方法的映射。
  • 在处理请求时,使用映射路由到预期的方法。

理解流程的一个简单技巧(是的,Java 有时太神奇了)是安装断点并查看调用堆栈。

【讨论】:

  • 感谢您的回答,但是,问题不在于处理器的功能或注释,而只是关于何时以及由谁调用处理器?示例答案:它由 Java Runtime 在类加载时运行。或者:它由库本身在任意时间调用。
【解决方案2】:

annotation processor 在编译时运行。调用javac 时,用户传递-processor 命令行选项,然后javac 调用处理器。注释处理器可以发出错误、创建文件(包括 Java 代码文件),甚至修改现有代码。除了上面链接的 Oracle 文档之外,您可能还想查看教程,例如 Baeldung's

有些框架直接解释注解,所以你不需要编写自己的注解处理器。

为了影响运行时行为,您的代码可以反射性地读取注释;在这种情况下,编译时不会运行注释处理器。

【讨论】:

  • 你的意思是编译器不只是编译处理器(生成字节码)吗?它也运行它?那件事真的让我吃惊:)
  • 也感谢 Baelgung 的文章,但是该文章深入到了 @Retention(RetentionPolicy.SOURCE) 示例,但是我的问题主要是关于 @Retention(RetentionPolicy.RUNTIME) 案例。
  • 您已编辑您的问题,说它与运行时保留有关,但这不会改变问题或答案。术语“注释处理”是指编译时处理。无论注释的保留是什么,编译时注释处理都适用。
  • 好吧,我们来看一个例子,@GetMapping 应该保存 http 请求路径中的一些文本和我们控制器中的方法之间的映射,对吧?因为根据您的评论,它是在编译时运行的,它必须为映射生成一些外部文件,对吗?在运行时,Spring Boot Web 将读取该文件以将请求重定向到其预期的控制器方法。但问题是,第一次读取提到的外部文件是什么时候?是在第一个http请求上吗?或者在我们的 Spring Boot 应用程序启动的某个时刻有某种初始化?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-11
  • 1970-01-01
  • 1970-01-01
  • 2014-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多