为什么 JPMS 允许注解类型作为服务

Why does JPMS allow annotation types as services

在介绍 JPMS 服务时,Java 语言规范第 7.7.4 节指出 "The service type must be a class type, an interface type, or an annotation type."

我很难理解允许注释的意义。我的理解是,JPMS 的服务概念是我们期望在运行时 select 实现的东西。看来,为了有用,实现至少需要有可能成为不同于原始 class 的东西,以标识所请求的服务。但我相信注释不能使用 "extends" 所以这永远不会发生?由此,我相信,如果我尝试使用注释类型创建服务,我将不可避免地遇到这样一种情况,即服务查找可能返回的唯一内容,例如 SomeAnnotation.class 就是 SomeAnnotation。这似乎毫无意义,所以我必须假设我遗漏了一些东西。

任何人都可以阐明这一点,并可能提供注释如何成为 "service" 的示例吗?

虽然在 Java 中注释接口不能显式扩展任何接口(但它总是隐式扩展 java.lang.annotation.Annotation),但它可以被实现。 IE。在句法上可以编写一个实现注释接口的具体 class,尽管根据 JLS 9.6. Annotation Types 这样的 class 不代表注释类型:

a subclass or subinterface of an annotation type is never itself an annotation type

因此我认为最初的问题可以归结为“为什么有人要显式实现注释接口?”。这个问题已经在 SO: Use cases for implementing annotations. The accepted answer there proposes to do this in order to partially overcome the limitation that a value of an annotation element must be either a constant expression, or a class literal, or an enum constant (see JLS 9.7.1. Normal Annotations) 上被问到和回答了:人们可以实现一个注释接口 "annotate" 实现 class 带有一个 "annotation" ,其中包括采取的动态数据,例如来自配置文件、数据库等。显然,这种技术还需要对读取注释的代码进行 更改,因为 class 实现注释接口实际上并不是注释,但它的实例可以用作注释的实例,就好像它已被检索一样,例如通过 java.lang.Class.getAnnotationsByType.

看来您又错过了服务商的补充。在命名模块中,服务提供者可以 return 来自静态方法的实现:

  • If the service provider declares a provider method, then the service loader invokes that method to obtain an instance of the service provider. A provider method is a public static method named "provider" with no formal parameters and a return type that is assignable to the service's interface or class.

    In this case, the service provider itself need not be assignable to the service's interface or class.

来自 ServiceLoader

因此以下方法可行:

module Example.Module {
    uses example.Anno;
    provides example.Anno with example.AnnoProvider;
}
package example;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface Anno {
    int value();
}
package example;

@Anno(42)
public class AnnoProvider {
    public static Anno provider() {
        return AnnoProvider.class.getAnnotation(Anno.class);
    }
}
package example;

import java.util.ServiceLoader;

public class ServiceUser {
    public static void main(String[] args) {
        for(Anno a: ServiceLoader.load(Anno.class)) {
            System.out.println(a.value());
        }
    }
}