D'introduction et de mise en Œuvre de base
Tout d'abord, vous allez avoir besoin d'au moins un URLStreamHandler. Ce sera fait d'ouvrir la connexion à une URL donnée. Remarquez que c'est simplement appelé Handler
; cela vous permet de spécifier java -Djava.protocol.handler.pkgs=org.my.protocols
et il sera automatiquement repris, à l'aide de la "simple" nom du package le protocole pris en charge (dans ce cas "classpath").
L'utilisation de la
new URL("classpath:org/my/package/resource.extension").openConnection();
Code
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();
}
}
Problèmes de lancement
Si vous êtes comme moi, vous ne voulez pas compter sur une propriété définie dans le lancement d'obtenir de vous quelque part (dans mon cas, je tiens à garder mes options ouvertes comme Java WebStart - c'est pourquoi j'ai besoin de tout cela).
Solutions/Améliorations
Manuel Gestionnaire de code de spécification
Si vous contrôlez le code, vous pouvez le faire
new URL(null, "classpath:some/package/resource.extension", new org.my.protocols.classpath.Handler(ClassLoader.getSystemClassLoader()))
et ce sera d'utiliser votre gestionnaire pour ouvrir la connexion.
Mais encore une fois, c'est moins que satisfaisant, tant que vous n'avez pas besoin d'une URL pour ce faire, vous voulez faire cela, parce que certains lib vous ne pouvez pas (ou ne voulez pas) de contrôle veut url...
JVM Gestionnaire d'enregistrement
L'option ultime est d'enregistrer un URLStreamHandlerFactory
qui se chargera de toutes les url à travers la 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);
}
}
Pour enregistrer le gestionnaire, appelez URL.setURLStreamHandlerFactory()
avec votre configurés en usine. Alors n' new URL("classpath:org/my/package/resource.extension")
comme le premier exemple et vous allez loin.
JVM Gestionnaire de Problème d'Enregistrement
Notez que cette méthode ne peut être appelée qu'une seule fois par la JVM, et notez bien que Tomcat va utiliser cette méthode pour enregistrer un JNDI gestionnaire (autant que je sache). Essayez Jetty (je serai); au pire, vous pouvez utiliser la première méthode, puis il a de travailler autour de vous!
Licence
J'ai communiqué ce dans le domaine public, et vous demandons, si vous souhaitez modifier qui vous démarrez un projet OSS quelque part et commentaire ici avec plus de détails. Une meilleure mise en œuvre serait d'avoir un URLStreamHandlerFactory
qui utilise ThreadLocal
s pour stocker URLStreamHandler
s par Thread.currentThread().getContextClassLoader()
. Je vais même vous donner mes modifications et les classes de test.
Maintenant, donnez-moi beaucoup de votes! :)