Введение и базовая реализация
Во-первых, вам понадобится хотя бы URLStreamHandler. Это фактически откроет соединение с данным URL. Обратите внимание, что это просто называется Handler
; это позволяет вам указать, java -Djava.protocol.handler.pkgs=org.my.protocols
и он будет автоматически выбран, используя «простое» имя пакета в качестве поддерживаемого протокола (в данном случае «classpath»).
использование
new URL("classpath:org/my/package/resource.extension").openConnection();
Код
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();
}
}
Проблемы с запуском
Если вы чем-то похожи на меня, вы не хотите полагаться на свойство, установленное при запуске, чтобы получить вас куда-то (в моем случае мне нравится держать свои параметры открытыми, как Java WebStart - вот почему
мне все это нужно ).
Обходные пути / Улучшения
Спецификация обработчика кода вручную
Если вы контролируете код, вы можете сделать
new URL(null, "classpath:some/package/resource.extension", new org.my.protocols.classpath.Handler(ClassLoader.getSystemClassLoader()))
и это будет использовать ваш обработчик, чтобы открыть соединение.
Но опять же, это менее чем удовлетворительно, так как вам не нужен URL для этого - вы хотите сделать это, потому что какая-то библиотека, которую вы не можете (или не хотите) контролировать, требует URL ...
Регистрация обработчика JVM
Окончательный вариант - зарегистрировать, URLStreamHandlerFactory
который будет обрабатывать все URL через 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);
}
}
Чтобы зарегистрировать обработчик, позвоните URL.setURLStreamHandlerFactory()
на настроенную фабрику. Затем сделайте new URL("classpath:org/my/package/resource.extension")
первый пример, и вы отправитесь в путь.
Проблема регистрации обработчика JVM
Обратите внимание, что этот метод может вызываться только один раз для JVM, и обратите внимание, что Tomcat будет использовать этот метод для регистрации обработчика JNDI (AFAIK). Попробуйте Jetty (я буду); в худшем случае, вы можете сначала использовать метод, а затем он должен работать вокруг вас!
Лицензия
Я передаю это в общественное достояние и спрашиваю, что если вы хотите изменить это, вы запускаете проект OSS где-то и комментируете здесь с деталями. Лучше реализация будет иметь , URLStreamHandlerFactory
что использует ThreadLocal
s для хранения URLStreamHandler
s для каждого Thread.currentThread().getContextClassLoader()
. Я даже дам вам свои модификации и тестовые классы.
com.github.fommil.common-utils
пакет, который я планирую вскоре обновить и выпустить через Sonatype.System.setProperty()
для регистрации протокола. ЛайкSystem.setProperty("java.protocol.handler.pkgs", "org.my.protocols");
Это должно сделать это.
источник
Я думаю, что это стоит своего ответа - если вы используете Spring, у вас уже есть это с
Как объяснено в весенней документации и указано в комментариях скаффмана.
источник
ResourceLoader.getResource()
больше подходит для этой задачи (ApplicationContext.getResource()
делегаты под нее под капотом)Вы также можете установить свойство программно во время запуска:
Используя этот класс:
Таким образом, вы получаете наименее навязчивый способ сделать это. :) java.net.URL всегда будет использовать текущее значение из системных свойств.
источник
java.protocol.handler.pkgs
системную переменную, может использоваться, только если обработчик нацелен на обработку еще не «известного» протокола, такого какgopher://
. Если целью является переопределение «популярного» протокола, напримерfile://
илиhttp://
, это может быть слишком поздно, поскольку вjava.net.URL#handlers
map уже добавлен «стандартный» обработчик для этого протокола. Таким образом, единственный выход - передать эту переменную в JVM.(Аналогично ответу Аздера , но немного другой такт.)
Я не верю, что есть предопределенный обработчик протокола для содержимого из classpath. (Так называемый
classpath:
протокол).Однако Java позволяет вам добавлять свои собственные протоколы. Это делается путем предоставления конкретных реализаций
java.net.URLStreamHandler
иjava.net.URLConnection
.В этой статье описывается, как может быть реализован пользовательский обработчик потока: http://java.sun.com/developer/onlineTraining/protocolhandlers/ .
источник
Я создал класс, который помогает уменьшить количество ошибок при настройке пользовательских обработчиков и использует преимущества системного свойства, поэтому нет проблем с вызовом метода первым или отсутствием нужного контейнера. Также есть класс исключений, если вы ошибаетесь:
источник
Вдохновитесь @Stephen https://stackoverflow.com/a/1769454/980442 и http://docstore.mik.ua/orelly/java/exp/ch09_06.htm
Использовать
просто создайте этот класс в
sun.net.www.protocol.classpath
пакет и запустите его в реализации Oracle JVM, чтобы работать как шарм.Если вы используете другую реализацию JVM, установите
java.protocol.handler.pkgs=sun.net.www.protocol
системное свойство.К вашему сведению: http://docs.oracle.com/javase/7/docs/api/java/net/URL.html#URL(java.lang.String,%20java.lang.String,%20int,%20java.lang .String)
источник
Конечно, решение с регистрацией URLStreamHandlers является наиболее правильным, но иногда требуется самое простое решение. Итак, я использую следующий метод для этого:
источник
Начиная с Java 9+, вы можете определить новое
URLStreamHandlerProvider
.URL
Класс использует структуру загрузчика службы , чтобы загрузить его во время выполнения.Создать провайдера:
Создайте файл с именем
java.net.spi.URLStreamHandlerProvider
вMETA-INF/services
каталоге с содержимым:Теперь класс URL будет использовать провайдера, когда он видит что-то вроде:
источник
Я не знаю, есть ли уже, но вы можете сделать это сами легко.
Этот пример другого протокола выглядит для меня как шаблон фасада. У вас есть общий интерфейс, когда есть разные реализации для каждого случая.
Вы можете использовать тот же принцип, создать класс ResourceLoader, который берет строку из файла свойств и проверяет наш собственный протокол.
удаляет myprotocol: с начала строки, а затем принимает решение о том, каким способом загрузить ресурс, и просто предоставляет вам ресурс.
источник
Расширение ответа Дилумса :
Без изменения кода вам, скорее всего, нужно следовать пользовательским реализациям интерфейсов, связанных с URL, как рекомендует Dilum. Чтобы упростить вам задачу, я могу порекомендовать посмотреть на источник ресурсов Spring Framework . Хотя код не в форме потокового обработчика, он был разработан для того, чтобы делать именно то, что вы хотите, и находится под лицензией ASL 2.0, что делает его достаточно дружественным для повторного использования в вашем коде с должным доверием.
источник
В приложении Spring Boot я использовал следующее, чтобы получить URL файла,
источник
Если у вас есть tomcat на пути к классам, это так просто:
Это зарегистрирует обработчики для протоколов "war" и "classpath".
источник
Я стараюсь избегать
URL
занятий и вместо этого полагаюсьURI
. Таким образом, для вещей, которые нужны,URL
где я хотел бы сделать Spring Resource, например поиск без Spring, я делаю следующее:Для создания URI вы можете использовать
URI.create(..)
. Этот способ также лучше, потому что вы контролируетеClassLoader
что будет делать поиск ресурса.Я заметил несколько других ответов, пытаясь проанализировать URL-адрес как строку для определения схемы. Я думаю, что лучше обойти URI и использовать его для анализа.
На самом деле, я недавно подал заявку на выпуск Spring Source, прося их отделить свой код ресурса от других ресурсов
core
Spring.источник