In Java, resources can be loaded using various URL protocols, enabling separation between resource loading and the application using it. A URL is represented as a simple string, making resource loading highly configurable.
Is there a protocol to load resources using the current classloader? This is similar to the Jar protocol, but without specifying a specific jar or class folder.
This can be achieved using a custom URLStreamHandler, which opens a connection to a given URL. The Handler is named simply as "Handler," allowing automatic pickup when specified using java -Djava.protocol.handler.pkgs=org.my.protocols.
Basic Implementation:
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 { 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(); } }
Usage:
new URL("classpath:org/my/package/resource.extension").openConnection();
Manual Code Handler Specification:
If the code is controlled, the handler can be specified manually:
new URL(null, "classpath:some/package/resource.extension", new org.my.protocols.classpath.Handler(ClassLoader.getSystemClassLoader()))
JVM Handler Registration:
The most comprehensive solution is to register a URLStreamHandlerFactory that handles all URLs across the JVM:
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<>(); addHandler(protocol, urlHandler); } public void addHandler(String protocol, URLStreamHandler urlHandler) { protocolHandlers.put(protocol, urlHandler); } public URLStreamHandler createURLStreamHandler(String protocol) { return protocolHandlers.get(protocol); } }
Then call URL.setURLStreamHandlerFactory() with the configured factory to register the handler.
JVM Handler Registration Issue:
This method can only be called once per JVM, and Tomcat may attempt to register its JNDI handler. Using Jetty or a custom URLStreamHandlerFactory with a ThreadLocal approach is recommended.
License:
The solution is released to the public domain, with a request to start an OSS project for modifications.
The above is the detailed content of How to Load Resources from the Classpath Using a Custom URL Protocol in Java?. For more information, please follow other related articles on the PHP Chinese website!