【问题标题】:Finding all classes implementing a specific interface [duplicate]查找实现特定接口的所有类[重复]
【发布时间】:2012-04-16 23:43:18
【问题描述】:

我正在开发一个应用程序(Quartz 调度程序),其中我们有一个负责实际执行工作的作业类,我们需要在 Quartz 中创建触发器时告诉/传递作业类的名称调度程序。

我想为所有想要使用 API 的人提供一个扩展点(除了我将作为 API 的一部分提供的一些通用作业之外)。这个想法是创建一个(标记)接口,如果有人想将他们的类声明为调度程序作业类,他们所要做的就是(声明)实现该接口。

我不确定如何找到遵循合同的类(通过实现接口),以便将它们显示给想要在调度程序中安排触发器的用户。

我的要求不是在运行时加载类,而是显示实现所需接口的类的用户列表,以便用户可以选择类并将类名传递给调度程序。最后是 Quartz 调度器负责创建一个类的实例。

任何人都可以建议我如何实现上述目标,或者有没有其他更好的方法来实现我想要做的事情?

编辑

我浏览了ServiceLoader 的文档,似乎为了实现一项服务,必须在 META-INF 文件夹中创建一个具有实现类名称的文件,这让我认为,如果我的 API 需要 20 个不同的实现,他必须在文件中放入 20 个条目,这对我来说似乎对最终用户来说是很多额外的工作,因为每个作业类都将创建用于执行特定的作业,并且可能有 100 个作业类。

如果我的假设是错误的,请纠正我。

【问题讨论】:

标签: java jakarta-ee quartz-scheduler


【解决方案1】:

你可以找到答案here

我可以建议使用 org.reflections

enter link description here

Reflections reflections = new Reflections("com.mycompany");    
Set<Class<? extends MyInterface>> classes = reflections.getSubTypesOf(MyInterface.class);

【讨论】:

  • 感谢您的输入,我正在浏览 ServiceLocator 文档,似乎对于我的界面(服务)的每个实施,最终用户都必须将条目放入文件中以便可以加载,是就像开发人员想要 20 个这样的实现,他/她需要将所有这些实现名称放在文件中,这对最终用户来说似乎有很多工作。
【解决方案2】:

我有类似的需求,我想确保创建的任何实现某个接口的类始终是真正可序列化的。我创建了一个 JavaClassFinder,它遍历类路径中的所有目录,并找到所有可分配给我关心的接口的类。这是一个代码sn-p:

public <T> List<Class<? extends T>> findAllMatchingTypes(Class<T> toFind) {
    foundClasses = new ArrayList<Class<?>>();
    List<Class<? extends T>> returnedClasses = new ArrayList<Class<? extends T>>();
    this.toFind = toFind;
    walkClassPath();
    for (Class<?> clazz : foundClasses) {
        returnedClasses.add((Class<? extends T>) clazz);
    }
    return returnedClasses;
}

如果有帮助,我很乐意与您分享代码。唯一的缺点是这只会处理 .class 文件——我没有添加该功能来解压 .jars 并从那里读取类文件。 (但添加它不会是一个巨大的项目。)

更新:我检查了上面的源代码,发现它依赖于我们标准实用程序库中的许多帮助类。为了方便起见,我压缩了所有需要的代码,您可以从JavaClassFinder.zip 下载。这将直接在 Eclipse 中设置,您可以获取所需的任何代码部分。

您将在项目中找到一个名为 JavaClassFinderTest.java 的 JUnit3 测试,它向您展示了 JavaClassFinder 类的特性和用法。运行 Junit 测试所需的唯一外部依赖项是 Junit。

此实用程序的基本用法:

    JavaClassFinder classFinder = new JavaClassFinder();
    List<Class<? extends MyTagInterface>> classes = classFinder.findAllMatchingTypes(MyTagInterface.class);

这将为您提供一个列表,其中包含类路径中可从“MyTagInterface.class”(例如)分配的任何类。希望这会有所帮助。

【讨论】:

  • 缺少“walkClassPath”方法。请问可以提供吗?
  • @YvesMartin:Yves,我更新了我的答案,包括所有下载原始代码的链接。它可能比您想要的要多,但它是一个完整的工作版本。
  • @SamGoldberg 您在这里设计的出色实用程序。
  • @shashankaholic:谢谢 - 我很想知道你是否能从中得到任何用处。我们使用它作为单元测试套件的一部分来测试特定类型的所有子类是否真正可序列化。 (我发现仅仅实现 Serializable 并不能保证一个类的实例可以成功序列化。)
  • @SamGoldberg:我使用了你的实用程序,它工作得非常好,除了在 web 应用程序中。我在 JavaClassFinder 类中看到了这个代码if (System.getProperties().containsKey(CUSTOM_CLASS_PATH_PROPERTY)) { // LOG.debug("getClassPathRoots(): using custom classpath property to search for classes"); classPath = System.getProperty(CUSTOM_CLASS_PATH_PROPERTY); } else { classPath = System.getProperty(JAVA_CLASS_PATH_PROPERTY); },似乎它的类路径是 tomcat 的“bootstrap.jar” .我想知道有没有办法在 web 应用程序中使用这个实用程序
【解决方案3】:

使用 Java SPI 机制可能是最好的(标准)方法,请参阅Javadoc。不方便(这也是一个不错的功能)是它希望定义扩展的 Jars 将它们列在 META-INF/services/your.fully.qualified.Interface 中。

我能想到的唯一其他方法是遍历所有 ClassLoader,希望您能够列出其中的文件,加载类文件,并查看它们是否实现了您的接口 - 这不是一件好事。

【讨论】:

    【解决方案4】:

    我认为 org.reflections 是 Alex Stybaev 提到的正确解决方案,您不需要在属性文件中引用这些类。

    另一种方法(我会采用)是Spring,因为无论如何我都在为我的应用程序使用 Spring,因此不需要任何额外的依赖项。

    您可以在此处找到解决 Spring 问题的提示(以及其他 cmets 或答案中的替代方法):

    在您的问题 heikkim 和 polypiel 的 cmets 中,还链接到有答案的问题,用 Spring 解决它:

    【讨论】:

      【解决方案5】:

      根据Find Java classes implementing an interface的回答,我用了http://software.clapper.org/javautil/:非常快,非常好用。

      【讨论】:

        【解决方案6】:

        要在纯 java 中这样做,最正确的答案已经被投票(来自 sam goldberg 2012 年 4 月 10 日)

        但是他的完整代码是不必要的复杂。我使用了他的想法并将 ClassFinder 推到了那里: http://icedtea.classpath.org/hg/icedtea-web/file/0527ad4eb2dd/netx/net/sourceforge/jnlp/controlpanel/ClassFinder.java

        注意 - 这将适用于独立应用程序(或任何使用带有 jars 和 dirs 的常规类路径的应用程序)而不是在 ServerContainer 中。

        如果您的应用程序在网络服务器中运行,您需要知道您的战争/耳朵的位置并在那里搜索。或者您必须询问您的父类劳德他从哪里获得您的(和其他)资源。

        第二个注意事项 - 我正在过滤最终位置类以仅匹配 netx 和 icedtea-web,因为我不会搜索依赖项。因此,如果您需要包含 rt.jar,请 rmeove thsoe 过滤器。或者如果您根本不需要它,则完全删除 bootclasspath。

        【讨论】:

          猜你喜欢
          • 2014-04-05
          • 2010-12-17
          • 2010-09-30
          • 2018-07-01
          • 2019-10-16
          • 2016-02-15
          • 2015-04-07
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多