【问题标题】:How to get resource files when loading a jar using an URLClassLoader?使用 URLClassLoader 加载 jar 时如何获取资源文件?
【发布时间】:2014-04-16 22:32:50
【问题描述】:

我编写了一个应用程序来管理几个以 jar 形式提供的插件。我使用 URLClassLoader 加载插件类,它按预期工作。

但是现在我正在编写一个插件来加载一些存储在 jar 中的资源。如果我将此插件作为独立应用程序启动,一切正常,但如果我从我的应用程序内部启动它,当我尝试打开资源 InputStream 时,我会得到一个 NullPointerException

我这样打开流:

this.getClass().getResourceAsStream("/templates/template.html");

我的 Eclipse 项目结构如下:

src
|
+ My source files
resources
|
+ templates
  |
  + template.html

以下加载我的插件:

private List<Class<?>> loadClasses(final File[] jars) {
    List<Class<?>> classes = new ArrayList<Class<?>>();
    URL[] urls = getJarURLs(jars);
    URLClassLoader loader = new URLClassLoader(urls);

    for (File jar : jars) {
        JarFile jarFile = null;

        try {
            jarFile = new JarFile(jar);
        } catch (IOException e) {
            // Skip this jar if it can not be opened
            continue;
        }

        Enumeration<JarEntry> entries = jarFile.entries();

        while (entries.hasMoreElements()) {
            JarEntry entry = entries.nextElement();

            if (isClassFile(entry.getName())) {
                String className = entry.getName().replace("/", ".").replace(".class", "");
                Class<?> cls = null;

                try {
                    cls = loader.loadClass(className);
                } catch (ClassNotFoundException e) {
                    // Skip this jar if a class inside it can not be loaded
                    continue;
                }

                classes.add(cls);
            }
        }

        try {
            jarFile.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    try {
        loader.close();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    return classes;
}

/**
 * Checks if a path points to a class file or not.
 * 
 * @param path the filename to check
 * @return {@code true} if the path points to a class file or {@code false}
 *         if not
 */
private boolean isClassFile(final String path) {
    return path.toLowerCase().endsWith(".class") && !path.toLowerCase().contains("package-info");
}

然后我使用 newInstance() 从这些类中创建实例。

我认为插件 jar 的根路径与应用程序的根路径不同,或者没有加载 jar 文件的所有内容或两者兼而有之......

有人可以帮我吗?

【问题讨论】:

  • this.getClass().getResource("/templates/template.html); 在尝试访问 jar 中的内容时对我来说很好。

标签: java jar


【解决方案1】:

首先要注意,使用getClass().getResource(...) 也会委托给ClassLoader,它也负责加载资源。使用哪个类加载器?它与加载类的类加载器相同。点。

在您的代码中,您构建了一个URLClassLoader 来加载一些类。因此,如果上述调用来自插件内部的类,那么相同的URLClassLoader 将用于加载资源。

这一切似乎都很好......但你犯了一个小错误。在加载结束时,您还关闭了加载程序。这将防止对loadClassgetResource 的后续调用返回任何有意义的内容。事实上,它可以为 null,因为现在加载器无法再加载资源了。

结论:不要关闭URLClassLoader,如果您仍然需要它以进行加载。而是保留对此类加载器的引用并在程序运行时结束时将其关闭。

【讨论】:

  • 感谢您的回答!这听起来合乎逻辑。我今天完成了工作,但明天我会检查这个。
  • 好的,这就是解决方案,谢谢!我对此还有另一个问题:假设我有两个插件,它们的 jar 中都有这个 /template/template.html 资源。 ClassLoader 如何确定他必须服务的资源?他是否足够聪明,可以检测到这些类来自不同的罐子?还是我必须为每个 jar 创建一个新的 ClassLoader
  • 如果请求资源的类来自不同的JAR,并且这些不同的JAR由不同的类加载器加载,那么它们会自动加载正确的资源。
猜你喜欢
  • 2010-10-22
  • 2017-10-09
  • 2019-02-08
  • 2023-03-31
  • 2011-06-07
  • 2015-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多