Wprowadzenie i podstawowe wdrożenie
Po pierwsze, potrzebujesz przynajmniej URLStreamHandler. To faktycznie otworzy połączenie z danym adresem URL. Zauważ, że jest to po prostu nazywane Handler
; pozwala to określić java -Djava.protocol.handler.pkgs=org.my.protocols
i zostanie on automatycznie pobrany, używając „prostej” nazwy pakietu jako obsługiwanego protokołu (w tym przypadku „ścieżka klasy”).
Stosowanie
new URL("classpath:org/my/package/resource.extension").openConnection();
Kod
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();
}
}
Uruchom problemy
Jeśli masz coś takiego jak ja, nie chcesz polegać na nieruchomości będącej w zestawie z uruchomieniem, aby dostać się gdzieś (w moim przypadku, jak zachować moje opcje otworzyć jak Java Web Start - dlatego
ja potrzebuję to wszystko ).
Obejścia / ulepszenia
Instrukcja obsługi kodu obsługi
Jeśli kontrolujesz kod, możesz to zrobić
new URL(null, "classpath:some/package/resource.extension", new org.my.protocols.classpath.Handler(ClassLoader.getSystemClassLoader()))
a to użyje twojego programu obsługi do otwarcia połączenia.
Ale znowu, to jest mniej niż zadowalające, ponieważ nie potrzebujesz do tego adresu URL - chcesz to zrobić, ponieważ niektóre biblioteki, których nie możesz kontrolować (lub nie chcesz) kontrolować, chcą adresów URL ...
Rejestracja JVM Handler
Ostateczną opcją jest zarejestrowanie pliku, URLStreamHandlerFactory
który będzie obsługiwał wszystkie adresy URL w 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<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);
}
}
Aby zarejestrować program obsługi, zadzwoń URL.setURLStreamHandlerFactory()
do skonfigurowanej fabryki. Zrób new URL("classpath:org/my/package/resource.extension")
więc pierwszy przykład i już nie ma go.
Problem z rejestracją modułu obsługi JVM
Należy pamiętać, że tę metodę można wywołać tylko raz dla JVM, i należy pamiętać, że Tomcat użyje tej metody do zarejestrowania procedury obsługi JNDI (AFAIK). Spróbuj Jetty (będę); w najgorszym wypadku możesz najpierw użyć tej metody, a potem musi ona obejść cię!
Licencja
Udostępniam to do domeny publicznej i proszę, jeśli chcesz zmodyfikować, rozpocznij gdzieś projekt OSS i skomentuj tutaj ze szczegółami. Lepszą implementacją byłoby posiadanie s URLStreamHandlerFactory
używającego ThreadLocal
s do przechowywania URLStreamHandler
s dla każdego Thread.currentThread().getContextClassLoader()
. Dam ci nawet moje modyfikacje i klasy testowe.
com.github.fommil.common-utils
pakietu, który planuję wkrótce zaktualizować i wydać za pośrednictwem Sonatype.