【问题标题】:Class discovery, reflection, jars and jnlp类发现、反射、jars 和 jnlp
【发布时间】:2011-01-05 17:47:32
【问题描述】:

在我们的系统中,我们有一个插件机制允许我们在运行时实例化未知的类。

在类路径中提供目录或jar,系统能够探索包含的类,如果类实现了特定的接口,它可以被实例化并用作插件。

所有东西都打包成罐子,运行良好。但是,当尝试将其捆绑为 webstart 应用程序时,这种机制似乎失效了。

更具体地说,类的发现似乎不再起作用了:

public static Collection<String> getAllClassFiles()
{
    Collection<String> all_files = new ArrayList<String>();

    String pathSep = System.getProperty("path.separator");
    String classpath = System.getProperty("java.class.path");

    for (String path : classpath.split(pathSep))
    {
        File filepath = new File(path);

        if (filepath.isDirectory()) 
        {
            all_files.addAll(dirContent(filepath));
        } 
        else if (path.endsWith(".jar")) 
        {

            JarFile jar;
            try {
                jar = new JarFile(filepath);
            } 
            catch (IOException e) {
                Log.warning("WARNING: " + filepath + " could not be opened!");
                continue;
            }

            for (Enumeration<JarEntry> entries = jar.entries(); entries
                    .hasMoreElements();)
            {
                JarEntry entry = entries.nextElement();
                if (entry.getName().endsWith(".class"))
                    all_files.add(entry.getName());
            }
        } 
        else if (path.endsWith(".class")) {
            all_files.add(path);
        } 
        else {
            Log.warning("Warning: corrupt classpath entry: " + path);
        }

    }
    return all_files;
}

所以......这在直接使用 jar 调用系统时有效......但不再使用 webstart,尽管所有 jar 都已签名并包含在内。

知道如何让它与 webstart 一起工作吗?

【问题讨论】:

  • 没有错误...只是返回一个空列表
  • ...显然,这是因为使用 java webstart 时类路径消失了。它只变成: java.class.path = /usr/lib/jvm/java-6-sun-1.6.0.06/jre/lib/deploy.jar 当我转储系统/部署属性时,我看不到任何痕迹“我的”类路径也没有原始 jar 的任何信息……那么,如何收集可用类的列表?

标签: java reflection jar java-web-start


【解决方案1】:

可能幸运地获得了上下文类加载器并尝试获取其 URL[] - 然后流式传输内容。

我认为这也不是一个好主意。 Java 不是围绕以这种方式反映内容而构建的。但是提供的可能不太优雅,可以读取元数据文件,例如使用Thread.getContextClassLoader().getResources("META-INF/plugins.txt"),您可以在其中定义要实例化的类。

或者,更精简,使用 ServiceLoader。

根据您的 claspath 和 jars,无论如何这比急切加载每个类要快...

【讨论】:

  • 我喜欢您指出的 ServiceLoader 方式......但是,它有两个弱点:首先,您必须在特定文件中维护所有插件实现的列表。然后,您必须插入一个特殊的机制,以便它在开发时也可以工作,而不仅仅是在 jar 中。我同意两者都可以被规避......但它是最终的解决方案......嗯,不太好。
  • 没错,你必须维护两个信息源,与类的接口或注解和“元”文件。但是枚举类路径上的每个文件可能确实很昂贵。我在开发时这样做没有困难,例如在 eclipse 中。您只需将“META-INF/services”文件夹添加到 src 文件夹,任何声明的服务都在类路径中 - 就像在运行时一样。它与罐子一起导出,你不必再关心了。
  • 虽然这似乎是一种令人满意的方法,但它的问题比我最初认识到的要多。首先,它在获取列表时为每个服务创建一个实例。无法使用 ServiceLoader 获取类列表,您可以直接获取实例。这可能很耗时且容易出错。其次,您无法获得一个服务的多个实例(不重新加载所有其他实例)
  • 您必须在间接级别上看到这一点:就像在您的普通反射示例中您“创建”一个类(确切地说是很多)一样,您应该在这里创建一个“工厂”。因此,只需提供具有“createService”方法的对象。
  • 是的,我知道......但这增加了一层复杂性......我同意,它不是很复杂,但仍然需要为每个插件添加一些代码行......所以我们将有:一个文本文件,列出将实例化服务的工厂……我的意思是……这没什么不好,但我感觉我们正在逐渐消失。如果我可以简单地获取 jar 中的文件列表,那么所有这些都将消失。
猜你喜欢
  • 1970-01-01
  • 2016-10-25
  • 2012-02-18
  • 1970-01-01
  • 2011-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-29
相关资源
最近更新 更多