URL组成
URL格式: protocol://[authority]hostname:port/resource?queryString
说明:每种协议对应一种特定handler进行解析处理,JDK内置了HTTP 、 File 、 FTP和Jar等协议的。
Handler
作用:每个Handler解析一种特定的协议,获取资源;
命名规范: Handler类的命名模式为 [包路径].[协议].Handler,JDK内置Handler的包路径为“sun.net.www.protocol”,如下图所示:
创建过程:
- 首先,如果创建URL时指定了Handler,则使用该Handler;
- 其次,如果设定了URLStreamHandlerFactory,则根据Protocol从其获取对应Handler实例;
- 最后,根据系统参数java.protocol.handler.pkgs指定的类创建Handler实例;
if (handler == null &&
(handler = getURLStreamHandler(protocol)) == null) {
throw new MalformedURLException("unknown protocol: " + protocol);
}
this.handler = handler;
设置包路径创建Handler
通过 JVM 启动参数 -D java.protocol.handler.pkgs 来设置 URLStreamHandler 实现类的包路径,例如 -D java.protocol.handler.pkgs=com.acme.protocol , 代表处理实现类皆在这个包下。如果需要多个包的话,那么使用“ |” 分割。比如 -D java.protocol.handler.pkgs=com.acme.protocol|com.acme.protocol2 。 SUN 的 JDK 内部实现类均是在 sun.net.www.protocol. 包下,不必设置。 路径下的协议实现类,采用先定义先选择的原则 。
if (handler == null) {
String packagePrefixList = null;
packagePrefixList
= java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction(
protocolPathProp,""));
if (packagePrefixList != "") {
packagePrefixList += "|";
}
// REMIND: decide whether to allow the "null" class prefix
// or not.
packagePrefixList += "sun.net.www.protocol";
StringTokenizer packagePrefixIter =
new StringTokenizer(packagePrefixList, "|");
while (handler == null &&
packagePrefixIter.hasMoreTokens()) {
String packagePrefix =
packagePrefixIter.nextToken().trim();
try {
String clsName = packagePrefix + "." + protocol +
".Handler";
Class<?> cls = null;
try {
cls = Class.forName(clsName);
} catch (ClassNotFoundException e) {
ClassLoader cl = ClassLoader.getSystemClassLoader();
if (cl != null) {
cls = cl.loadClass(clsName);
}
}
if (cls != null) {
handler =
(URLStreamHandler)cls.newInstance();
}
} catch (Exception e) {
// any number of exceptions can get thrown here
}
}
}
自定义URL协议
实现URLStreamHandlerFactory或者设置系统参数“java.protocol.handler.pkgs”即可。
参考: