在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的地方使用它,只需更新属性文件即可。


当前回答

灵感来自@Stephen https://stackoverflow.com/a/1769454/980442 和http://docstore.mik.ua/orelly/java/exp/ch09_06.htm

使用

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

只需将这个类创建到sun.net.www.protocol.classpath包中,并将其运行到Oracle JVM实现中即可。

package sun.net.www.protocol.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(URL u) throws IOException {
        return Thread.currentThread().getContextClassLoader().getResource(u.getPath()).openConnection();
    }
}

如果您正在使用另一个JVM实现,请设置java.protocol.handler.pkgs=sun.net.www.protocol系统属性。

仅供参考: URL http://docs.oracle.com/javase/7/docs/api/java/net/URL.html(以% 20以% 20 int, % 20以)

其他回答

我认为这是值得回答的问题——如果您正在使用Spring,那么您已经有了这个功能

Resource firstResource =
    context.getResource("http://www.google.fi/");
Resource anotherResource =
    context.getResource("classpath:some/resource/path/myTemplate.txt");

就像春季文档中解释的,斯卡夫曼在评论中指出的那样。

再延伸一下Dilums的回答:

在不更改代码的情况下,您可能需要按照Dilum的建议,使用URL相关接口的自定义实现。为了简化事情,我建议查看Spring Framework的资源的源代码。虽然代码不是流处理程序的形式,但它的设计完全是为了做您想做的事情,并且是在ASL 2.0许可下进行的,这使得它足够友好,可以在您的代码中重用。

我创建了一个类,它有助于减少设置自定义处理程序的错误,并利用系统属性,因此不存在首先调用方法或不在正确容器中的问题。如果你做错了,还有一个异常类:

CustomURLScheme.java:
/*
 * The CustomURLScheme class has a static method for adding cutom protocol
 * handlers without getting bogged down with other class loaders and having to
 * call setURLStreamHandlerFactory before the next guy...
 */
package com.cybernostics.lib.net.customurl;

import java.net.URLStreamHandler;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Allows you to add your own URL handler without running into problems
 * of race conditions with setURLStream handler.
 * 
 * To add your custom protocol eg myprot://blahblah:
 * 
 * 1) Create a new protocol package which ends in myprot eg com.myfirm.protocols.myprot
 * 2) Create a subclass of URLStreamHandler called Handler in this package
 * 3) Before you use the protocol, call CustomURLScheme.add(com.myfirm.protocols.myprot.Handler.class);
 * @author jasonw
 */
public class CustomURLScheme
{

    // this is the package name required to implelent a Handler class
    private static Pattern packagePattern = Pattern.compile( "(.+\\.protocols)\\.[^\\.]+" );

    /**
     * Call this method with your handlerclass
     * @param handlerClass
     * @throws Exception 
     */
    public static void add( Class<? extends URLStreamHandler> handlerClass ) throws Exception
    {
        if ( handlerClass.getSimpleName().equals( "Handler" ) )
        {
            String pkgName = handlerClass.getPackage().getName();
            Matcher m = packagePattern.matcher( pkgName );

            if ( m.matches() )
            {
                String protocolPackage = m.group( 1 );
                add( protocolPackage );
            }
            else
            {
                throw new CustomURLHandlerException( "Your Handler class package must end in 'protocols.yourprotocolname' eg com.somefirm.blah.protocols.yourprotocol" );
            }

        }
        else
        {
            throw new CustomURLHandlerException( "Your handler class must be called 'Handler'" );
        }
    }

    private static void add( String handlerPackage )
    {
        // this property controls where java looks for
        // stream handlers - always uses current value.
        final String key = "java.protocol.handler.pkgs";

        String newValue = handlerPackage;
        if ( System.getProperty( key ) != null )
        {
            final String previousValue = System.getProperty( key );
            newValue += "|" + previousValue;
        }
        System.setProperty( key, newValue );
    }
}


CustomURLHandlerException.java:
/*
 * Exception if you get things mixed up creating a custom url protocol
 */
package com.cybernostics.lib.net.customurl;

/**
 *
 * @author jasonw
 */
public class CustomURLHandlerException extends Exception
{

    public CustomURLHandlerException(String msg )
    {
        super( msg );
    }

}

从Java 9+及更高版本开始,您可以定义一个新的URLStreamHandlerProvider。URL类使用服务加载器框架在运行时加载它。

创建一个提供者:

package org.example;

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

public class ClasspathURLStreamHandlerProvider extends URLStreamHandlerProvider {

    @Override
    public URLStreamHandler createURLStreamHandler(String protocol) {
        if ("classpath".equals(protocol)) {
            return new URLStreamHandler() {
                @Override
                protected URLConnection openConnection(URL u) throws IOException {
                    return ClassLoader.getSystemClassLoader().getResource(u.getPath()).openConnection();
                }
            };
        }
        return null;
    }

}

在META-INF/services目录中创建一个名为java.net.spi.URLStreamHandlerProvider的文件,内容如下:

org.example.ClasspathURLStreamHandlerProvider

现在URL类将在看到如下内容时使用提供程序:

URL url = new URL("classpath:myfile.txt");
URL url = getClass().getClassLoader().getResource("someresource.xxx");

这样就行了。