Вступ та основна реалізація
По-перше, вам знадобиться принаймні 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-адреса - ви хочете це зробити, тому що якась lib, яку ви не можете (або не хочете) контролювати, хоче URL-адреси ...
Реєстрація JVM Handler
Кінцева опція - це зареєструвати a, 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.