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

Tob*_*itt 7 java java-9 java-annotations java-module

在介绍 JPMS 服务时,Java 语言规范的 7.7.4 节指出“服务类型必须是类类型、接口类型或注释类型”。

我正在努力理解允许注释的意义。我的理解是服务的 JPMS 概念是我们期望在运行时选择实现的东西。看起来,为了有用,实现至少需要有可能是不同于标识所请求服务的原始类的东西。但我相信注释不能使用“扩展”,所以这永远不会发生?从那以后,我相信如果我尝试使用注释类型创建服务,我将不可避免地遇到这样一种情况,即服务查找可能返回的唯一内容,例如 SomeAnnotation。类将完全是 SomeAnnotation。这似乎毫无意义,所以我必须假设我错过了一些东西。

任何人都可以阐明这一点,也许可以提供注释如何成为“服务”的示例?

Hol*_*ger 5

您似乎错过了服务提供商的另一个补充。在命名模块中,服务提供者可以从静态方法返回实现:

  • 如果服务提供者声明了提供者方法,则服务加载器调用该方法来获取服务提供者的实例。提供者方法是名为“提供者”的公共静态方法,没有形式参数和可分配给服务接口或类的返回类型。

    在这种情况下,服务提供者本身不需要分配给服务的接口或类。

ServiceLoader

因此,以下将起作用:

module Example.Module {
    uses example.Anno;
    provides example.Anno with example.AnnoProvider;
}
Run Code Online (Sandbox Code Playgroud)
package example;

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

@Retention(RetentionPolicy.RUNTIME)
public @interface Anno {
    int value();
}
Run Code Online (Sandbox Code Playgroud)
package example;

@Anno(42)
public class AnnoProvider {
    public static Anno provider() {
        return AnnoProvider.class.getAnnotation(Anno.class);
    }
}
Run Code Online (Sandbox Code Playgroud)
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());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Mal*_*ale 4

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

注释类型的子类或子接口本身绝不是注释类型

因此,我相信最初的问题可以归结为“为什么有人想要显式实现注释接口? ”。这个问题已经在 SO: Use Cases for Implementing Comments上被提出和回答。那里接受的答案建议这样做,以便部分克服注释元素的值必须是常量表达式、类文字或枚举常量的限制(请参阅JLS 9.7.1. 普通注释): 一个可以实现注释接口,以使用“注释”来“注释”实现类,该“注释”包括例如从配置文件、数据库等获取的动态数据。显然,这种技术还需要对读取注释的代码进行少量更改,如实现注释接口的类实际上并未被注释,而是它的实例可以用作注释的实例,就好像它是通过例如检索的一样java.lang.Class.getAnnotationsByType