在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的地方使用它,只需更新属性文件即可。
我试图避免URL类,而是依赖URI。因此,对于需要URL的事情,我想做Spring资源查找,我做以下工作:
public static URL toURL(URI u, ClassLoader loader) throws MalformedURLException {
if ("classpath".equals(u.getScheme())) {
String path = u.getPath();
if (path.startsWith("/")){
path = path.substring("/".length());
}
return loader.getResource(path);
}
else if (u.getScheme() == null && u.getPath() != null) {
//Assume that its a file.
return new File(u.getPath()).toURI().toURL();
}
else {
return u.toURL();
}
}
要创建一个URI,可以使用URI.create(..)。这种方式也更好,因为您控制了将执行资源查找的ClassLoader。
我注意到其他一些答案试图将URL解析为字符串以检测该方案。我认为最好是传递URI并使用它来解析。
事实上,我在不久前提出了一个问题,要求Spring Source将他们的资源代码从核心中分离出来,这样你就不需要所有其他Spring的东西了。
你也可以在启动时以编程方式设置属性:
final String key = "java.protocol.handler.pkgs";
String newValue = "org.my.protocols";
if (System.getProperty(key) != null) {
final String previousValue = System.getProperty(key);
newValue += "|" + previousValue;
}
System.setProperty(key, newValue);
使用这个类:
package org.my.protocols.classpath;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
public class Handler extends URLStreamHandler {
@Override
protected URLConnection openConnection(final URL u) throws IOException {
final URL resourceUrl = ClassLoader.getSystemClassLoader().getResource(u.getPath());
return resourceUrl.openConnection();
}
}
这样你就得到了侵入性最小的方法。url将始终使用系统属性中的当前值。