简体   繁体   English

如何从 java 类路径中的网络目录正确加载资源?

[英]How do I correctly load resources from a network directory in the java classpath?

Our java application relies on some resources which are available on a network share.我们的 java 应用程序依赖于网络共享上可用的一些资源。 This network share is located on the classpath, and the resources are read at runtime using MyClass.class.getResourceAsStream("/myfile.jpg") .此网络共享位于类路径上,并在运行时使用MyClass.class.getResourceAsStream("/myfile.jpg")读取资源。

java -Djava.class.path=\\myserver\myshare:C:\myjar.jar MainClass

When the share is available at startup, everything runs smoothly.当共享在启动时可用时,一切运行顺利。 Image and properties files which are located in the share can be read using getResourceAsStream() .可以使用getResourceAsStream()读取位于共享中的图像和属性文件。 However, if the share is not online when the application starts, even if the share comes online before any resources are read , they cannot be read using getResourceAsStream() .但是,如果应用程序启动时共享未在线,即使共享在读取任何资源之前已在线,也无法使用getResourceAsStream()读取它们。

Doing some digging using eclispse + decompiler, I noticed one difference.使用 eclispse + 反编译器进行一些挖掘,我注意到了一个区别。 The default classloader inherits from URLClassLoader, and its ucp member ( URLClassPath ) contains a list of URLClassPath.Loader instances.默认类加载器继承自 URLClassLoader,其ucp成员 ( URLClassPath ) 包含URLClassPath.Loader实例的列表。 In the first scenario, it contains a URLClassPath.FileLoader and a URLClassPath.JarLoader .在第一个场景中,它包含一个URLClassPath.FileLoader和一个URLClassPath.JarLoader In the second scenario, it only contains a jar loader.在第二种情况下,它只包含一个 jar 加载程序。

It's like java determines that the classpath entry is invalid and completely discards it.就像 java 确定类路径条目无效并完全丢弃它。

Why is this?为什么是这样? How can I avoid it?我怎样才能避免它?

Update I am unable to change the mechanism by which we are loading resources because of a few reasons:更新由于以下几个原因,我无法更改我们加载资源的机制:

  1. There are far too many areas which currently load files this way for me change at the moment目前以这种方式加载文件的区域太多了,我现在改变了
  2. There are situations where by the resource is actually being loaded by a third party component在某些情况下,资源实际上是由第三方组件加载的

I have no problem creating a custom class loader, I just need some guidance on how to do it.创建自定义 class 加载程序没有问题,我只需要一些有关如何操作的指导。

I tried with this, but was unable to get expected results:我尝试了这个,但无法获得预期的结果:

import java.net.URL;
import java.net.URLClassLoader;

public class MyUrlClassLoader extends URLClassLoader {
    public MyUrlClassLoader(ClassLoader parent) {
        super(new URL[0], parent);
        System.out.println("MyUrlClassLoader ctor");
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        System.out.println("url find class " + name);
        return super.findClass(name);
    }

    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        System.out.println("url load class " + name);
        return super.loadClass(name);
    }

    @Override
    public URL getResource(String name) {
        System.out.println("url get resource " + name);
        return super.getResource(name);
    }
}


import java.net.URL;

public class ClassLoaderMain {
    public static void main(String[] args) throws ClassNotFoundException {
        URL url = ClassLoaderMain.class.getResource("/myfile.txt");
        System.out.print("Loaded? ");
        System.out.println(url != null);

        System.out.println(ClassLoaderMain.class.getClassLoader().toString());
        System.out.println(MyUrlClassLoader.class.getClassLoader().toString());
        System.out.println(FakeClass.class.getClassLoader().toString());
    }
}

When I run java -cp. -Djava.system.class.loader=MyUrlClassLoader ClassLoaderMain当我运行java -cp. -Djava.system.class.loader=MyUrlClassLoader ClassLoaderMain java -cp. -Djava.system.class.loader=MyUrlClassLoader ClassLoaderMain

This outputs:这输出:

MyUrlClassLoader ctor
url load class java.lang.System
url load class java.nio.charset.Charset
url load class java.lang.String
url load class ClassLoaderMain
Loaded? true
sun.misc.Launcher$AppClassLoader@923e30
sun.misc.Launcher$AppClassLoader@923e30
sun.misc.Launcher$AppClassLoader@923e30

So my class loader is being created, and load class is being called, but it doesn't appear to be the class loader for the classes it is loading?因此,正在创建我的 class 加载器,并且正在调用加载 class,但它似乎不是它正在加载的类的 class 加载器?

I ended up resolving this by creating my own ClassLoader , deriving from URLClassLoader.我最终通过创建自己的ClassLoader来解决这个问题,该 ClassLoader 派生自 URLClassLoader。

import java.io.File;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;

public class CustomClassLoader extends URLClassLoader {

    public CustomClassLoader(ClassLoader parent) {
        // System classloader will filter inaccessible URLs. 
        // Force null parent to avoid using system classloader.
        super(createURLReferences(), null);
    }

    /**
     * Build an array of URLs based on the java.class.path property.
     * @return An array of urls to search for classes.
     */
    private static URL[] createURLReferences() {
        String classpath = System.getProperty("java.class.path");
        String[] classpathEntries = classpath.split(System.getProperty("path.separator"));
        List<URL> urls = new ArrayList<URL>();
        for (String classpathEntry : classpathEntries) {
            File classpathFile = new File(classpathEntry);
            URI uri = classpathFile.toURI();
            try {
                URL url = uri.toURL();
                urls.add(url);
            } catch (MalformedURLException e) {
                System.out.println("Ignoring classpath entry: " + classpathEntry);
            }
        }

        return urls.toArray(new URL[urls.size()]);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM