URL.setURLStreamHandlerFactory
我正在使用带有嵌入式Jetty的可执行jar开发Web应用程序。
我的jar包含一个依赖的jar。(jar子里的jar)
我引用了由Eclipse开发的JarRsrcLoader
和RsrcURLStreamHandlerFactory
。
JarRsrcLoader
使用URL#setURLStreamHandlerFactory(RsrcURLStreamHandlerFactory)
来解析rsrc
协议。
从而它可以解析jar的类路径。
但是,作为副作用解决通常的协议变得不可能。
例如file:xxxx
或jar:xxxx
。
RsrcURLStreamHandlerFactory
具有setURLStreamHandlerFactory
方法。
也许我认为我应该为这个方法设置默认工具。
我不知道这个方法是什么设置的。
在Java运行时中只注册了一个URLStreamHandlerFactory
实现实例,因此该实现必须了解所有支持的协议。
默认的Oracle / Sun行为不是以这种方式实现的,而是直接在java.net.URL
类中实现的。 因此,您不能简单地将默认实现注入RsrcURLStreamHandlerFactory
的链式工厂。 第一部分答案。
java.net.URL
getURLStreamHandler
方法根据其类名的命名策略加载协议X
的实现,默认为sun.net.www.protocol.X.Handler
如果你看一下jre/lib/rt.jar
,你会发现:
sun/net/www/protocol/ftp/Handler.class sun/net/www/protocol/gopher/Handler.class sun/net/www/protocol/mailto/Handler.class sun/net/www/protocol/netdoc/Handler.class sun/net/www/protocol/http/Handler.class sun/net/www/protocol/jar/Handler.class sun/net/www/protocol/file/Handler.class
用于协议URLStreamHandler
选择的基本包列表来自java.protocol.handler.pkgs
Java系统属性。 我邀请您从JDK java/net/URL.java
读取java/net/URL.java
的完整源代码以了解详细信息。
-
所以正确的方法(无论IBM / Eclipse做了什么)是保留默认机制并在命令行上设置例如
-Djava.protocol.handler.pkgs="com.company.product.protocol"
(如果您有权限/认可这样做)。 使用名为com.company.product.protocol.rsrc.Handler
使用JarRsrcLoader
的URLStreamHandler
实现,您可以完成工作。 -
备用选项是将
URLStreamHandlerFactory
实现编写为RsrcURLStreamHandlerFactory
的链式工厂,RsrcURLStreamHandlerFactory
灵感来自URL.getURLStreamHandler
源代码。 例如,您可以阅读这个旧的JBoss代码 。 它通过在注册工厂之前预加载其他已知 (或使用过的 )协议来依赖URL
内部处理程序缓存。 在我看来,只是丑陋。
警告 : RsrcURLStreamHandler
已经用自己的10行“版本”替换了URLStreamHandler.parseURL
的原始180行代码,而没有调用super.parseURL
。 当然,它不尊重URL连接规范! 请注意,根据URL的使用方式,您可能会遇到错误。
从Java 9开始,您可以使用SPI来提供处理程序:
URL(String,String,int,String)构造函数JavaDoc描述搜索算法:
如果应用程序先前已将URLStreamHandlerFactory实例设置为流处理程序工厂,则使用协议字符串作为参数调用该实例的createURLStreamHandler方法以创建流协议处理程序。
如果尚未设置URLStreamHandlerFactory,或者工厂的createURLStreamHandler方法返回null,则使用ServiceLoader机制使用系统类加载器定位URLStreamHandlerProvider实现。 提供程序所在的顺序是特定于实现的,并且实现可以自由地缓存所定位的提供程序。 从createURLStreamHandler抛出的ServiceConfigurationError,Error或RuntimeException(如果遇到)将传播到调用线程。 使用协议字符串调用每个提供程序的createURLStreamHandler方法(如果已实例化),直到提供程序返回非null,或者所有提供程序已用尽。
- 如果上一步未能找到协议处理程序,则构造函数将读取系统属性的值:java.protocol.handler.pkgs
- 如果上一步未能找到协议处理程序,则构造函数会尝试加载内置协议处理程序。 如果此类不存在,或者该类存在但它不是URLStreamHandler的子类,则抛出MalformedURLException。
保证在搜索路径上存在以下协议的协议处理程序:http,https,file和jar