Introduction et implémentation de base
Tout d'abord, vous allez avoir besoin d'au moins un URLStreamHandler. Cela ouvrira en fait la connexion à une URL donnée. Notez que cela s'appelle simplement Handler
; cela vous permet de spécifier java -Djava.protocol.handler.pkgs=org.my.protocols
et il sera automatiquement récupéré, en utilisant le nom de package "simple" comme protocole pris en charge (dans ce cas "chemin de classe").
Usage
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 pour vous trouver quelque part (dans mon cas, j'aime garder mes options ouvertes comme Java WebStart - c'est pourquoi
j'ai besoin de tout cela ).
Solutions de contournement / améliorations
Spécification du gestionnaire de code manuel
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 cela utilisera votre gestionnaire pour ouvrir la connexion.
Mais encore une fois, c'est moins que satisfaisant, car vous n'avez pas besoin d'une URL pour le faire - vous voulez le faire parce qu'une bibliothèque que vous ne pouvez pas (ou ne voulez pas) contrôler veut des URL ...
Inscription du gestionnaire JVM
L'option ultime est d'enregistrer un URLStreamHandlerFactory
qui gérera toutes les URL à travers le 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 usine configurée. Alors faisnew URL("classpath:org/my/package/resource.extension")
comme le premier exemple et c'est parti.
Problème d'enregistrement du gestionnaire JVM
Notez que cette méthode ne peut être appelée qu'une seule fois par JVM, et notez bien que Tomcat utilisera cette méthode pour enregistrer un gestionnaire JNDI (AFAIK). Essayez Jetty (je le serai); au pire, vous pouvez d'abord utiliser la méthode et ensuite elle doit fonctionner autour de vous!
Licence
Je publie ceci dans le domaine public, et je demande que si vous souhaitez modifier que vous démarrez un projet OSS quelque part et commentez ici avec les détails. Une meilleure implémentation serait d'avoir un URLStreamHandlerFactory
qui utilise ThreadLocal
s pour stocker URLStreamHandler
s pour chacun Thread.currentThread().getContextClassLoader()
. Je vais même vous donner mes modifications et mes cours de test.
com.github.fommil.common-utils
package que je prévois de mettre à jour et de publier bientôt via Sonatype.System.setProperty()
pour enregistrer le protocole. CommeSystem.setProperty("java.protocol.handler.pkgs", "org.my.protocols");
Ça devrait le faire.
la source
Je pense que cela vaut sa propre réponse - si vous utilisez Spring, vous l'avez déjà avec
Comme expliqué dans la documentation du printemps et souligné dans les commentaires de skaffman.
la source
ResourceLoader.getResource()
ApplicationContext.getResource()
Vous pouvez également définir la propriété par programme lors du démarrage:
Utilisation de cette classe:
Ainsi, vous obtenez le moyen le moins intrusif de le faire. :) java.net.URL utilisera toujours la valeur actuelle des propriétés du système.
la source
java.protocol.handler.pkgs
variable système ne peut être utilisé que si le gestionnaire visait à traiter un protocole pas encore "connu" tel quegopher://
. Si l'intention est de remplacer le protocole "populaire", commefile://
ouhttp://
, il pourrait être trop tard pour le faire, carjava.net.URL#handlers
map est déjà ajouté un gestionnaire "standard" pour ce protocole. La seule solution consiste donc à transmettre cette variable à JVM.(Similaire à la réponse d' Azder , mais un tact légèrement différent.)
Je ne crois pas qu'il existe un gestionnaire de protocole prédéfini pour le contenu du chemin de classe. (Le soi-disant
classpath:
protocole).Cependant, Java vous permet d'ajouter vos propres protocoles. Cela se fait en fournissant des implémentations concrètes
java.net.URLStreamHandler
etjava.net.URLConnection
.Cet article décrit comment un gestionnaire de flux personnalisé peut être implémenté: http://java.sun.com/developer/onlineTraining/protocolhandlers/ .
la source
J'ai créé une classe qui aide à réduire les erreurs de configuration des gestionnaires personnalisés et tire parti de la propriété système, il n'y a donc aucun problème à appeler une méthode en premier ou à ne pas être dans le bon conteneur. Il y a aussi une classe d'exception si vous vous trompez:
la source
Inspire by @Stephen https://stackoverflow.com/a/1769454/980442 et http://docstore.mik.ua/orelly/java/exp/ch09_06.htm
Utiliser
il suffit de créer cette classe dans le
sun.net.www.protocol.classpath
package et de l'exécuter dans l'implémentation JVM Oracle pour fonctionner comme un charme.Si vous utilisez une autre implémentation JVM, définissez la
java.protocol.handler.pkgs=sun.net.www.protocol
propriété système.Pour info: http://docs.oracle.com/javase/7/docs/api/java/net/URL.html#URL(java.lang.String,%20java.lang.String,%20int,%20java.lang .Chaîne)
la source
La solution avec l'enregistrement d'URLStreamHandlers est la plus correcte, bien sûr, mais parfois la solution la plus simple est nécessaire. Donc, j'utilise la méthode suivante pour cela:
la source
Depuis Java 9+ et plus, vous pouvez définir un nouveau
URLStreamHandlerProvider
. leURL
classe utilise le framework de chargeur de service pour le charger au moment de l'exécution.Créez un fournisseur:
Créez un fichier appelé
java.net.spi.URLStreamHandlerProvider
dans leMETA-INF/services
répertoire avec le contenu:Maintenant, la classe URL utilisera le fournisseur lorsqu'elle verra quelque chose comme:
la source
Je ne sais pas s'il y en a déjà un, mais vous pouvez le faire vous-même facilement.
Cet exemple de protocoles différents me ressemble à un motif de façade. Vous disposez d'une interface commune lorsqu'il existe différentes implémentations pour chaque cas.
Vous pouvez utiliser le même principe, créer une classe ResourceLoader qui prend la chaîne de votre fichier de propriétés et recherche un de nos protocoles personnalisés
supprime le myprotocole: dès le début de la chaîne, puis décide de la manière de charger la ressource et vous donne simplement la ressource.
la source
Une extension de la réponse de Dilums :
Sans changer le code, vous devrez probablement poursuivre les implémentations personnalisées des interfaces liées aux URL comme le recommande Dilum. Pour simplifier les choses pour vous, je peux recommander de regarder la source des ressources de Spring Framework . Bien que le code ne soit pas sous la forme d'un gestionnaire de flux, il a été conçu pour faire exactement ce que vous cherchez à faire et est sous la licence ASL 2.0, ce qui le rend assez convivial pour être réutilisé dans votre code avec tout le crédit nécessaire.
la source
Dans une application Spring Boot, j'ai utilisé ce qui suit pour obtenir l'URL du fichier,
la source
Si vous avez tomcat sur le chemin de classe, c'est aussi simple que:
Cela enregistrera les gestionnaires pour les protocoles "war" et "classpath".
la source
J'essaie d'éviter la
URL
classe et me fie plutôt à moiURI
. Ainsi, pour les choses qui ont besoin de l'URL
endroit où je voudrais faire Spring Resource comme une recherche sans Spring, je fais ce qui suit:Pour créer un URI, vous pouvez utiliser
URI.create(..)
. Cette méthode est également meilleure car vous contrôlez la fonctionClassLoader
qui effectuera la recherche de ressources.J'ai remarqué d'autres réponses essayant d'analyser l'URL en tant que chaîne pour détecter le schéma. Je pense qu'il vaut mieux passer l'URI et l'utiliser à la place.
J'ai en fait déposé un problème il y a quelque temps auprès de Spring Source en les suppliant de séparer leur code de ressource
core
afin que vous n'ayez pas besoin de tous les autres trucs de Spring.la source