如何在 Spring Boot 构建期间或启动期间验证注释?

How to validate annotations during build or during startup on Spring Boot?

例如,假设我有一个 @TimedMillis 和一个 @TimedSeconds 注释。他们所做的是记录方法执行持续时间,一个以毫秒为单位,另一个以秒为单位。

将它们放在同一个方法上没有任何意义。一个方法可以有这些注解之一,或者他可以有 none 个,但不能同时有两个。

如何在构建过程中检查方法是否同时具有它们(最好)?如果在构建期间不可能,我如何在启动期间执行此操作并阻止应用程序启动?我已经看到休眠在启动期间这样做了。虽然它没有阻止应用程序启动,但确实阻止了应用程序工作。

您可以使用 reflections 库轻松扫描包及其所有子包,以查找 类 包含使用特定注释进行注释的方法。

然后您可以在您认为合适的任何地方注入验证逻辑。

例如你可以:

  1. 添加反射依赖:
<dependency>
    <groupId>org.reflections</groupId>
    <artifactId>reflections</artifactId>
    <version>0.9.12</version>
</dependency>
  1. 添加验证逻辑,甚至比 Spring 启动 bootstrap 如果需要,像这样:
  public static void main(String[] args) {
    validateAnnotations();
    SpringApplication.run(ExampleApplication.class, args);
  }

  private static void validateAnnotations() {
    Set<Method> annotatedMethods = 
      new Reflections("com.example", new MethodAnnotationsScanner())
      .getMethodsAnnotatedWith(TimedMillis.class);
    
    annotatedMethods.stream()
    .filter(method -> method.getDeclaredAnnotationsByType(TimedSeconds.class).length > 0)
    .findFirst()
    .ifPresent(method -> {
      throw new IllegalStateException("Invalid annotations for method " + method);
    });
  }

还有一个替代选项 - 通过注释本身使其不可能。
这种方法假定 @TimedMillis 和 @TimedSeconds 实际上非常相似 - 并且可以重构为单个注释。
为了实现这样的功能,可以引入新的注释 - 将所需的时间单位作为提供的值。

@Target({ElementType.METHOD})
public @interface Timed {

    /**
     * Defines time unit of duration.
     *
     * @return duration time unit
     */
    TimeUnit timeUnit();
}

这将有助于实现所需的功能,因为不允许重复注释(仅当未使用 @Repeatable 标记时)

您可以定义自定义 annotation processor to do this validation. The annotation processing will occur at build time. Here is a nice tutorial on how to use the annotation processing API: https://www.baeldung.com/java-annotation-processing-builder