根据您的特定要求,在某些情况下,Java 的 service loader 机制可能会实现您的目标。
简而言之,它允许开发人员通过在 JAR/WAR 文件的 META-INF/services 目录中的文件中列出某个类来显式声明某个类的子类(或实现某个接口)。然后可以使用java.util.ServiceLoader 类发现它,当给定Class 对象时,将生成该类的所有已声明子类的实例(或者,如果Class 表示一个接口,则所有实现该接口的类)。
这种方法的主要优点是无需手动扫描整个类路径以查找子类 - 所有发现逻辑都包含在 ServiceLoader 类中,它只加载在 META-INF/services 中显式声明的类目录(不是类路径上的每个类)。
但也有一些缺点:
- 它不会找到所有子类,只会找到那些明确声明的子类。因此,如果您需要真正找到所有子类,这种方法可能不够用。
- 需要开发者明确声明
META-INF/services目录下的类。这会给开发人员带来额外的负担,并且容易出错。
-
ServiceLoader.iterator() 生成子类实例,而不是它们的 Class 对象。这会导致两个问题:
- 您对子类的构造方式没有任何发言权 - 无参数构造函数用于创建实例。
- 因此,子类必须具有默认构造函数,或者必须显式声明无参数构造函数。
显然,Java 9 将解决其中一些缺点(特别是与子类实例化有关的缺点)。
一个例子
假设您有兴趣查找实现接口com.example.Example 的类:
package com.example;
public interface Example {
public String getStr();
}
com.example.ExampleImpl 类实现了该接口:
package com.example;
public class ExampleImpl implements Example {
public String getStr() {
return "ExampleImpl's string.";
}
}
您可以通过创建包含文本com.example.ExampleImpl 的文件META-INF/services/com.example.Example 来声明类ExampleImpl 是Example 的实现。
然后,您可以获得Example 的每个实现的实例(包括ExampleImpl 的实例),如下所示:
ServiceLoader<Example> loader = ServiceLoader.load(Example.class)
for (Example example : loader) {
System.out.println(example.getStr());
}
// Prints "ExampleImpl's string.", plus whatever is returned
// by other declared implementations of com.example.Example.