对Java的URL类支持的协议进行扩展的方法

转载自   对Java的URL类支持的协议进行扩展的方法

 JAVA默认提供了对file,ftp,gopher,http,https,jar,mailto,netdoc协议的支持。当我们要利用这些协议来创建应用时,主要会涉及到如下几个类:java.net.URL、java.net.URLConnection、InputStream。URL类默认支持上述协议,但是有时候我们想自定义协议,怎么办呢?


Java提供了三种方法可以支持这个扩展

1、URL.setURLStreamHandlerFactory(URLStreamHandlerFactory)

      URLStreamHandlerFactory(java.net.URLStreamHandlerFactory),这是一个接口,定义如下:

package java.net;  /** * This interface defines a factory for {@code URL} stream * protocol handlers. * <p> * It is used by the {@code URL} class to create a * {@code URLStreamHandler} for a specific protocol. * * @author  Arthur van Hoff * @see     java.net.URL * @see     java.net.URLStreamHandler * @since   JDK1.0 */  
public interface URLStreamHandlerFactory {  /** * Creates a new {@code URLStreamHandler} instance with the specified * protocol. * * @param   protocol   the protocol ("{@code ftp}", *                     "{@code http}", "{@code nntp}", etc.). * @return  a {@code URLStreamHandler} for the specific protocol. * @see     java.net.URLStreamHandler */  URLStreamHandler createURLStreamHandler(String protocol);  
}  

此接口需要实现createURLStreamHandler(String protocol)方法,参数protocol为协议名称,返回URLStreamHandler( java.net.URLStreamHandler )抽象类,抽象方法定义如下:

abstract protected URLConnection openConnection(URL u) throws IOException;  
参数u为URL类型,URL.openConnection间接调用这个方法,返回URLConnection,然后可以获取InputStream进而获取相应的数据(资源)
示例如下:
URL.setURLStreamHandlerFactory(new URLStreamHandlerFactory() {  @Override  public URLStreamHandler createURLStreamHandler(String protocol) {  if("json".equals(protocol)){  return new URLStreamHandler(){  @Override  protected URLConnection openConnection(URL url) throws IOException {  return new URLConnection(url){  public InputStream getInputStream() throws IOException {  return new FileInputStream("d:/aaaa.txt");  }  @Override  public void connect() throws IOException {  //建立连接  }  };  }  };  }  else return null;  }  });  URL url = new URL("json://json.url.com");  
InputStream in = url.openConnection().getInputStream();  
System.out.println(in.read());  

上述代码判断如果协议(protocal)为json,则返回一个自定义的URLStreamHandler,否则返回null,对应其他Java本身已经支持的协议会不会造成影响呢?

我们且看URL的一个构造方法(URL(String protocol, String host, int port, String file,URLStreamHandler handler) 中类似):

public URL(URL context, String spec, URLStreamHandler handler)  throws MalformedURLException  
{  String original = spec;  int i, limit, c;  int start = 0;  String newProtocol = null;  boolean aRef=false;  boolean isRelative = false;  // Check for permission to specify a handler  if (handler != null) {  SecurityManager sm = System.getSecurityManager();  if (sm != null) {  checkSpecifyHandler(sm);  }  }  try {  limit = spec.length();  while ((limit > 0) && (spec.charAt(limit - 1) <= ' ')) {  limit--;        //eliminate trailing whitespace  }  while ((start < limit) && (spec.charAt(start) <= ' ')) {  start++;        // eliminate leading whitespace  }  if (spec.regionMatches(true, start, "url:", 0, 4)) {  start += 4;  }  if (start < spec.length() && spec.charAt(start) == '#') {  /* we're assuming this is a ref relative to the context URL. * This means protocols cannot start w/ '#', but we must parse * ref URL's like: "hello:there" w/ a ':' in them. */  aRef=true;  }  for (i = start ; !aRef && (i < limit) &&  ((c = spec.charAt(i)) != '/') ; i++) {  if (c == ':') {  String s = spec.substring(start, i).toLowerCase();  if (isValidProtocol(s)) {  newProtocol = s;  start = i + 1;  }  break;  }  }  // Only use our context if the protocols match.  protocol = newProtocol;  if ((context != null) && ((newProtocol == null) ||  newProtocol.equalsIgnoreCase(context.protocol))) {  // inherit the protocol handler from the context  // if not specified to the constructor  if (handler == null) {  handler = context.handler;  }  // If the context is a hierarchical URL scheme and the spec  // contains a matching scheme then maintain backwards  // compatibility and treat it as if the spec didn't contain  // the scheme; see 5.2.3 of RFC2396  if (context.path != null && context.path.startsWith("/"))  newProtocol = null;  if (newProtocol == null) {  protocol = context.protocol;  authority = context.authority;  userInfo = context.userInfo;  host = context.host;  port = context.port;  file = context.file;  path = context.path;  isRelative = true;  }  }  if (protocol == null) {  throw new MalformedURLException("no protocol: "+original);  }  // Get the protocol handler if not specified or the protocol  // of the context could not be used  if (handler == null &&  (handler = getURLStreamHandler(protocol)) == null) {  throw new MalformedURLException("unknown protocol: "+protocol);  }  this.handler = handler;  i = spec.indexOf('#', start);  if (i >= 0) {  ref = spec.substring(i + 1, limit);  limit = i;  }  /* * Handle special case inheritance of query and fragment * implied by RFC2396 section 5.2.2. */  if (isRelative && start == limit) {  query = context.query;  if (ref == null) {  ref = context.ref;  }  }  handler.parseURL(this, spec, start, limit);  } catch(MalformedURLException e) {  throw e;  } catch(Exception e) {  MalformedURLException exception = new MalformedURLException(e.getMessage());  exception.initCause(e);  throw exception;  }  
}  

代码87行,调用了getURLStreamHandler(protocol),此方法:

static URLStreamHandler getURLStreamHandler(String protocol) {  URLStreamHandler handler = handlers.get(protocol);  if (handler == null) {  boolean checkedWithFactory = false;  // Use the factory (if any)  if (factory != null) {  handler = factory.createURLStreamHandler(protocol);  checkedWithFactory = true;  }  // Try java protocol handler  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  }  }  }  synchronized (streamHandlerLock) {  URLStreamHandler handler2 = null;  // Check again with hashtable just in case another  // thread created a handler since we last checked  handler2 = handlers.get(protocol);  if (handler2 != null) {  return handler2;  }  // Check with factory if another thread set a  // factory since our last check  if (!checkedWithFactory && factory != null) {  handler2 = factory.createURLStreamHandler(protocol);  }  if (handler2 != null) {  // The handler from the factory must be given more  // importance. Discard the default handler that  // this thread created.  handler = handler2;  }  // Insert this handler into the hashtable  if (handler != null) {  handlers.put(protocol, handler);  }  }  }  return handler;  }  

代码段

if (factory != null) {

handler = factory.createURLStreamHandler(protocol);
checkedWithFactory = true;
}

这一段是从factory中获取相应协议的URLStreamHandler,如果获取不到,则从另一渠道获得(即不会对java已经支持的协议造成影响),就是我们讲的第2种方法

各个构造方法的调用关系代码如下:

//#1  
public URL(String spec) throws MalformedURLException {  this(null, spec);//调用#2 URL(URL context, String spec)  
}  
//#2  
public URL(URL context, String spec) throws MalformedURLException {  this(context, spec, null);调用#6 URL(URL context, String spec, URLStreamHandler handler)  
}  //#3  
public URL(String protocol, String host, int port, String file)  throws MalformedURLException  
{  this(protocol, host, port, file, null);//调用#6 RL(String protocol, String host, int port, String file,URLStreamHandler handler)  
}  //#4  
public URL(String protocol, String host, String file)  throws MalformedURLException {  this(protocol, host, -1, file);//调用#3 URL(String protocol, String host, int port, String file)  
}  //#5  
public URL(String protocol, String host, int port, String file,  URLStreamHandler handler)  throws MalformedURLException{  //....  
}  //#6  
public URL(URL context, String spec, URLStreamHandler handler) throws MalformedURLException{  //....  
}  //可以看出,实质性逻辑都在#5和#6方法 


2、 通过 JVM 启动参数 -Djava.protocol.handler.pkgs来设置 URLStreamHandler 实现类的包路径

比如-D java.protocol.handler.pkgs=com.myprotocol.pkgs0|com.myprotocol.pkgs1,多个用|分割,java默认的包为sun.net.www.protocol,设置了这个参数,会拼接在默认的包之后,即sun.net.www.protocol|com.myprotocol.pkgs0|com.myprotocol.pkgs1

看这段代码

if (handler == null) {  String packagePrefixList = null;  packagePrefixList  = java.security.AccessController.doPrivileged(  new sun.security.action.GetPropertyAction(  protocolPathProp,""));//protocolPathProp的值为java.protocol.handler.pkgs  if (packagePrefixList != "") {  packagePrefixList += "|";  }  // REMIND: decide whether to allow the "null" class prefix  // or not.  packagePrefixList += "sun.net.www.protocol";//拼接默认的pkgs  StringTokenizer packagePrefixIter =  new StringTokenizer(packagePrefixList, "|");  while (handler == null &&  packagePrefixIter.hasMoreTokens()) {//遍历pkgs  String packagePrefix =  packagePrefixIter.nextToken().trim();  try {  String clsName = packagePrefix + "." + protocol +  ".Handler";//类全名为pkgs.protocal.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  }  }  
}  

类的命名模式为 [pkgs].[protocol].Handler,比如默认实现” sun.net.www.protocol.[protocol].Handler”, 比如HTTP 协议的对应的处理类名为 -sun.net. www.protocol.http.Handler 

自定义协议例子如下:

package com.myprotocol.pkgs0.json;  import java.io.FileInputStream;  
import java.io.IOException;  
import java.io.InputStream;  
import java.net.URL;  
import java.net.URLConnection;  
import java.net.URLStreamHandler;  public class Handler extends URLStreamHandler {  @Override  protected URLConnection openConnection(URL u) throws IOException {  return new URLConnection(u) {  public InputStream getInputStream() throws IOException {  return new FileInputStream("d:/aaaa.txt");  }  @Override  public void connect() throws IOException {  // 建立连接  }  };  }  
}  
启动时命令:java -Djava.protocol.handler.pkgs=com.myp rotocol.pkgs0 其他参数 主类

3、构造方法URL((URL)null, "json://www.google.com",new URLStreamHandler(){...})

这种方法直接设置Handler,比较简单,不在赘述


代理Proxy

URLStreamHandler 覆盖openConnection(URL) openConnection(URL,Proxy) 两个方法即可



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/328732.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在.Net项目中使用Redis作为缓存服务

最近由于项目需要&#xff0c;在系统缓存服务部分上了redis&#xff0c;终于有机会在实际开发中玩一下&#xff0c;之前都是自己随便看看写写&#xff0c;很零碎也没沉淀下来什么&#xff0c;这次算是一个系统学习和实践过程的总结。 和Redis有关的基础知识 Redis是一个开源的分…

中国的程序员培训是不是有问题?

内容来源于&#xff0c;看最下面的出处&#xff0c;侵删 中国技术开放日的出海团对日本进行了为期一周的访问。笔者随行了头两天&#xff0c;参加Slush Asia大会&#xff0c;并访问了Gungho和Deloitte两家企业。虽然已经在日本生活了四年&#xff0c;但这样的体验却甚少&#x…

后台回调支付宝

https://blog.csdn.net/u012552275/article/details/78320051 网上找了一个可以起吊支付宝的appdemo &#xff0c;它集成了服务器端&#xff0c;我先将其分离为app和服务器端&#xff0c;保证app在接收参数后可以启调支付宝 &#xff08;保证app这边是正确的 不然出错都不知道…

解决高版本SpringBoot整合swagger时启动报错:Failed to start bean ‘documentationPluginsBootstrapper‘ 问题

一、控制台的报错信息 2021-12-29 15:15:04 [main] ERROR org.springframework.boot.SpringApplication - Application run failed org.springframework.context.ApplicationContextException: Failed to start bean documentationPluginsBootstrapper; nested exception is j…

java图片格式转化(例如jpg格式转化png)

转载自 java图片格式转化&#xff08;例如jpg格式转化png&#xff09; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.Scanner;import javax.imageio.*; public class FormatConversion {public static final Str…

微软开源PowerShell并支持Linux

建议在Wifi 环境下观看视频 class"video_iframe" data-vidtype"1" style" z-index:1; " height"375" width"500" frameborder"0" data-src"https://v.qq.com/iframe/preview.html?vidv0322g7kd3f&width…

招银网络科技笔试

记录一下 招银网络笔试 2017年09月11日 14:32:53 阅读数&#xff1a;2450 Part1. 30道单选 涉及Java&#xff0c;C&#xff0c;多线程&#xff0c;算法&#xff0c;数据结构&#xff0c;CPU&#xff0c;NP问题&#xff0c;SQL语句&#xff0c;IP地址转换&#xff0c;行测。…

mybatisGenerator逆向工程

一、在pom文件中导入依赖和generator插件 <dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency><dependency&…

2016最佳温情小说:雨还在下....

作者 | 李德霞 来源 | 小小说选刊 哗&#xff0c;一道闪电&#xff1b;轰&#xff0c;一个响雷。 暴雨倾盆&#xff0c;天地间浑沌一片…… 老大扑腾腾坐起来&#xff0c;心也跟着扑腾腾地跳。老大拉亮灯&#xff0c;推推身边的媳妇。媳妇一骨碌爬起来&#xff0c;咋&#xf…

java 中 image 和 byte[] 相互转换

转载自 java 中 image 和 byte[] 相互转换只需要一个存储了图片信息的二进制串&#xff08;byte[]&#xff09; 然后&#xff0c;这样&#xff1a; InputStream buffin new ByteArrayInputStream(/*二进制串*/, /*起始位置*/,/*二进制串长度*/)); BufferedImage img ImageIO…

招银网络

记录一下 招银网络笔试 2017年09月11日 14:32:53 阅读数&#xff1a;2451 Part1. 30道单选 涉及Java&#xff0c;C&#xff0c;多线程&#xff0c;算法&#xff0c;数据结构&#xff0c;CPU&#xff0c;NP问题&#xff0c;SQL语句&#xff0c;IP地址转换&#xff0c;行测。…

Java 文件和byte数组转换

转载自 Java 文件和byte数组转换 /** * 获得指定文件的byte数组 */ private byte[] getBytes(String filePath){ byte[] buffer null; try { File file new File(filePath); FileInputStream fis new FileInputStream(file); ByteArrayOutputStream bos new ByteAr…

json大文件导入数据库

json文件导入数据库 使用Navicat的客户端工具也可以实现json文件导入数据库&#xff0c;但是数据量大了之后&#xff0c;字段的值过于冗长可能会导致数据的截取&#xff0c;是的数据导入不是完整的。 所以另辟蹊径使用其他方法 创建一个新的工程用原始的jdbc实现数据的导入 一…

Docker for Windows使用简介

在上一篇文章中&#xff0c;通过演练指导的方式&#xff0c;介绍了在Docker中运行ASP.NET Core Web API应用程序的过程。本文将介绍Docker for Windows的使用。 先决条件 前两周时间&#xff0c;Docker发布了Docker for Windows的正式版&#xff0c;于是就可以在Windows下运行D…

pagehelper 不分页的解决方法

pagehelper 不分页的解 pagehelper PageHelper.startPage(1, 10);只对该语句以后的第一个查询语句得到的数据进行分页, 就算你在PageInfo pa new PageInfo("",对象);语句里面的对象是写的最终得到的数据,该插件还是只会对第一个查询所查询出来的数据进行分页 第一…

最近流行的12个笑话,好笑又有道理

来源 | 悦读文摘&#xff08;ID&#xff1a;yueduwz&#xff09; 01 一个盲人到亲戚家做客&#xff0c;天黑后&#xff0c;他的亲戚好心为他点了个灯笼&#xff0c;说&#xff1a;“天晚了&#xff0c;路黑&#xff0c;你打个灯笼回家吧&#xff01;” 盲人火冒三丈地说&#x…

java 从jar包中读取资源文件

转载自 java 从jar包中读取资源文件 在代码中读取一些资源文件(比如图片&#xff0c;音乐&#xff0c;文本等等)&#xff0c;在集成环境(Eclipse)中运行的时候没有问题。但当打包成一个可执行的jar包&#xff08;将资源文件一并打包&#xff09;以后&#xff0c;这些资源文件找…

json常用的转换

一、json字符串与map的相互转换 首先要导入依赖&#xff0c;用的是fastjson依赖 <dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.45</version> </dependency>json转map //第一…

JWT【JSON Web Token】 简述

JWT全称JSON Web Token[http://www.jwt.io/]&#xff0c;用于发送可通过数字签名和认证的东西&#xff0c;它包含一个紧凑的&#xff0c;URL安全的JSON对象&#xff0c;服务端可通过解析该值来验证是否有操作权限&#xff0c;是否过期等安全性检查。由于其紧凑的特点&#xff0…

Android增加自定义监听事件

适配器中 public interface ShippingDelOnClickListener {public void onClickListenerShippingDel(int position); }private ShippingDelOnClickListener mShippingDelOnClickListener;public void setShippingDelOnClickListener(ShippingDelOnClickListener shippingDelO…