当前位置: 首页 > 面试题库 >

从Java中的类路径加载资源的URL

程冥夜
2023-03-14
问题内容

在Java中,您可以使用相同的API,但使用不同的URL协议来加载各种资源:

file:///tmp.txt
http://127.0.0.1:8080/a.properties
jar:http://www.foo.com/bar/baz.jar!/COM/foo/Quux.class

这很好地将资源的实际加载与需要资源的应用程序分离开来,并且由于URL只是一个字符串,因此资源加载也很容易配置。

是否有使用当前类加载器加载资源的协议?这类似于Jar协议,除了我不需要知道资源来自哪个jar文件或类文件夹。

Class.getResourceAsStream("a.xml")当然可以使用来做到这一点,但这需要我使用不同的API,因此需要对现有代码进行更改。我希望能够在仅通过更新属性文件就可以为资源指定URL的所有地方使用它。


问题答案:

介绍和基本实现
首先,你将至少需要一个URLStreamHandler。这实际上将打开与给定URL的连接。注意,这简称为Handler; 这样你就可以指定java -Djava.protocol.handler.pkgs=org.my.protocols它,并且使用“简单”程序包名称作为受支持的协议(在这种情况下为“ classpath”)将自动将其提取。

用法

new URL("classpath:org/my/package/resource.extension").openConnection();

Code

package org.my.protocols.classpath;

import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;

/** A {@link URLStreamHandler} that handles resources on the classpath. */
public class Handler extends URLStreamHandler {
    /** The classloader to find resources from. */
    private final ClassLoader classLoader;

    public Handler() {
        this.classLoader = getClass().getClassLoader();
    }

    public Handler(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    @Override
    protected URLConnection openConnection(URL u) throws IOException {
        final URL resourceUrl = classLoader.getResource(u.getPath());
        return resourceUrl.openConnection();
    }
}

启动问题
如果你像我一样,就不想依靠启动中设置的属性来将你带到某个地方(就我而言,我想像Java WebStart一样保持打开选项-这就是为什么我需要所有这些内容)。
解决方法/增强功能
手册代码处理程序规范
如果你控制代码,则可以

new URL(null, "classpath:some/package/resource.extension", new org.my.protocols.classpath.Handler(ClassLoader.getSystemClassLoader()))

这将使用你的处理程序打开连接。

但这又不尽如人意,因为你不需要URL即可执行此操作-你之所以要这样做是因为你无法(或不想控制)某些lib想要url …

JVM处理程序注册

最终的选择是注册一个URLStreamHandlerFactory将处理jvm中所有URL的:

package my.org.url;

import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
import java.util.HashMap;
import java.util.Map;

class ConfigurableStreamHandlerFactory implements URLStreamHandlerFactory {
    private final Map<String, URLStreamHandler> protocolHandlers;

    public ConfigurableStreamHandlerFactory(String protocol, URLStreamHandler urlHandler) {
        protocolHandlers = new HashMap<String, URLStreamHandler>();
        addHandler(protocol, urlHandler);
    }

    public void addHandler(String protocol, URLStreamHandler urlHandler) {
        protocolHandlers.put(protocol, urlHandler);
    }

    public URLStreamHandler createURLStreamHandler(String protocol) {
        return protocolHandlers.get(protocol);
    }
}

要注册处理程序,请致电URL.setURLStreamHandlerFactory()你配置的工厂。然后new URL("classpath:org/my/package/resource.extension")像第一个例子一样去做。

JVM处理程序注册问题
请注意,每个JVM只能调用一次此方法,请注意,Tomcat将使用此方法注册JNDI处理程序(AFAIK)。试试Jetty(我会的);最坏的情况是,你可以先使用该方法,然后它必须在你周围解决!

License

我将其发布到公共领域,并询问是否要修改以在某个地方启动OSS项目并在此处提供详细信息。更好的实现是让每个URLStreamHandlerFactory使用ThreadLocal来存储。我什至会给你我的修改和测试课程。URLStreamHandlerThread.currentThread().getContextClassLoader()



 类似资料:
  • 我正在尝试将资源csv文件传递到我的Sprint Boot应用程序使用的jar中。尽管方法获取的资源参数=ReactiveWebContext资源[src/main/Resources/file.csv],但我总是得到该文件不存在的响应 > 在我的项目中,文件位于src/main/resources/file中。csv 正在应用中。属性,我定义: 在config类中: 在内部jar:Config类

  • 问:什么是加载资源的正确解决方案(从类路径和/或一般情况下)?Spring文档中提倡使用:http://docs.Spring.io/Spring/docs/current/spring-framework-reference/html/beans.html#context-introduction 问:为什么autowired字段仍然为空?

  • 问题内容: 是否有API可以获取类路径资源(例如,我将从中获得的资源)?理想情况下,我想将新的API与类路径资源一起使用。 问题答案: 这对我有用:

  • 是否有API来获取类路径资源(例如,我从)作为获取的类路径资源?理想情况下,我希望使用带有类路径资源的新的API。

  • 问题内容: 在关于类加载方法之间差异的一个流行答案中,乔恩·斯凯特(Jon Skeet)说, 类加载器资源路径始终被视为绝对路径。 一个更受欢迎的答案通过一个例子肯定了这一说法。 将所有路径视为绝对路径。因此,调用 和 都会在您的类路径中的以下位置查找文件: 。 忽略示例无法编译的事实,共识表明领先的正斜杠与ClassLoader无关。 一个简单的测试则相反。 我只是将路径添加到测试项目的类路径中

  • 问题内容: 以下是一些代码片段,这些片段指示我目前正在尝试什么,但是它不可靠。原则上,我认为因为您只能注册一次协议处理程序,偶尔其他库可能会先这样做。 xml-catalog.xml包含: 显然-xsd文件位于类路径中的正确位置。 问题答案: 解析器使用以下最小代码集来正常运行: 您可以选择将其指定为JVM参数: 该班是实现如下: 在请求资源时,使用正斜杠()很重要,这已由以下 堆栈溢出 问题回答