为什么 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.
因此以下方法可行:
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());
}
}
}
在介绍 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.
因此以下方法可行:
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());
}
}
}