java:解决URL.setURLStreamHandlerFactory只能被jvm调用一次的问题

如果你能找到这篇博客,你肯定是为实现URL协议扩展时自定义协议的StreamHandlerFactory注册问题而头痛。 一般而言,URL 的格式是: protocol://[authority]hostname:port/resource?queryString 常见协议头(protocol)有http,https,file。对应不同的协议,java都有提供默认URLStreamHandler对象来解析这些协议,如下图,这些位于rt.jar包中每一个package都对应一种协议,package下都有一个继承自URLStreamHandler的Handler类用于对应协议解析

如果要实现自己的协议,就需要自己写一个URLStreamHandler,如何写URLStreamHandler与具体项目需求相关,不是本文要讨论的重点。当我们想让自己写的URLStreamHandler生效,就需要将它注册到URL中,这篇文章《Java URL协议扩展实现》详细描述了两种机制,来实现URL协议扩展。 第一种方法就是用URL.setURLStreamHandlerFactory方法将自己的URLStreamHandlerFactory注册到URL类中。我打算采用的就是这种方式,因为这种方式相比jvm参数方式更加可控。 然而,根据URL.setURLStreamHandlerFactory方法的说明以及其代码可知,这个方法具有独占性,在JVM运行时只能被调用一次。(现在看来,这应该算是java的一个设计缺陷) 一般情况下,我们不一定能保证在自己调用URL.setURLStreamHandlerFactory时是第一次,所以调用很有可能失败。 怎么解决这个问题呢?Apache Commons Sandbox提供了一个解决方法,就是commons-jnet,它基本原理就是使用java reflect技术,强行改变URL中的私有成员变量factory(类型为URLStreamHandlerFactory)来保setURLStreamHandlerFactory能被成功调用,并且不破坏原有的factory。 common-jnet代码非常少,只有4个类,没有提供jar包,只是提供源码,从svn上checkout出来加入自己的项目代码就可以使用了

svn checkout http://svn.apache.org/repos/asf/commons/sandbox/jnet/trunk commons-jnet

具体的使用方式,common-jnet的官网上说明得非常明白也非常简单。 http://commons.apache.org/sandbox/commons-jnet/

找到common-jnet之前就发现org.eclipse.osgi中的EquinoxFactoryManager就是用相同的办法解决这个问题的,只是其中的代码混在一起不好摘出来。

参见 EquinoxFactoryManager.installURLStreamHandlerFactory方法和 EquinoxFactoryManager.forceURLStreamHandlerFactory方法的源码

参考资料:

《Java URL协议扩展实现》 apache.sandbox.commons-jnet

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏云计算教程系列

如何在Ubuntu 18.04上安装最新的MySQL

MySQL是一个着名的开源数据库管理系统,用于存储和检索各种流行应用程序的数据。MySQL是LAMP堆栈中的M,是一组常用的开源软件,也包括Linux,Apac...

1620
来自专栏hbbliyong

将Python脚本打包成可执行文件

本文主要就是介绍最后一种方式,.py和.pyc都比较简单,Python本身就可以搞定。将Python脚本打包成可执行文件有多种方式,本文重点介绍PyInstal...

731
来自专栏CSDN技术头条

自动化模式中的MySQL

原文:MySQL on Autopilot 作者:Tim Gross 翻译:孙薇 自动化模式(Autopilot Pattern)是一种设计应用与基础架构的方式...

2385
来自专栏北京马哥教育

Nginx动静分离实现负载均衡

使用Debian环境。安装Nginx(默认安装),一个web项目,安装tomcat(默认安装)等。

930
来自专栏枕边书

一键部署进化史

前言 ---- 之前的文章说过 由 PHP 转到 Java 之后,非常不适应的一点就是代码部署过程耗时长,调试不便,虽然可以使用 debug,但有时候还是需要修...

4018
来自专栏Java技术分享圈

本地安装谷歌的插件之 CRX格式插件离线安装

方法一 :开发模式安装 [亲测] 1.把下载后的.crx扩展名的离线Chrome插件的文件扩展名改成.zip或者.rar (如何查看Chrome插件的扩展名...

662
来自专栏金蝶云平台的专栏

Grunt :初次使用及前端构建经验

这是我们部门前端同学cobish的学习笔记,笔者编辑了一下并分享给大家。

3510
来自专栏猛牛哥的博客

Centos安装简单易用的端口转发工具:rinetd

5955
来自专栏武培轩的专栏

当你在浏览器地址栏输入一个URL后回车,将会发生的事情?

当我们在浏览器的地址栏输入 www.cnblogs.com ,然后回车,回车到看到页面到底发生了什么呢? 域名解析 --> 发起TCP的3次握手 --> 建立T...

3417
来自专栏KaliArch

Python利用sphinx构建个人博客

1850

扫码关注云+社区