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

在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();

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(我会的);最坏的情况是,你可以先使用该方法,然后它必须在你周围解决!

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

以上是 从Java中的类路径加载资源的URL 的全部内容, 来源链接: utcz.com/qa/422663.html

回到顶部