要让Java应用支持echo://、myproto://等非标准协议,需自定义URLStreamHandler重写parseURL解析host/port/path/query,并通过URLStreamHandlerFactory注册;同时实现URLConnection子类以控制连接逻辑,且工厂注册须早于任何URL实例化。

要让 Java 应用支持类似 echo://、myproto:// 这类非标准协议,并能解析其中的变量(如主机、端口、路径、查询参数),核心是自定义 URLStreamHandler 并配合 URLStreamHandlerFactory 注册。这不是简单字符串替换,而是要接管整个协议解析与连接建立逻辑。
协议变量需在 parseURL 中显式提取
URLStreamHandler 子类必须重写 parseURL(URL u, String spec, int start, int limit) 方法。Java 原生只识别 http/https/file 等协议,对自定义协议不会自动拆解 host/port/path/query —— 这些都得你手动做。
- 用
spec.substring(start, limit)获取协议后原始字符串(如"localhost:8000/hello?name=alice") - 按约定分隔符(如
:拆 host:port,/拆路径,?拆查询)逐段解析 - 调用
setURL(u, protocol, host, port, file, authority, ref)把结果填入 URL 对象内部字段,后续getHost()、getQuery()才能返回正确值
URLConnection 需继承并覆盖关键方法
仅解析 URL 不够,还得让 url.openConnection() 返回你能控制的连接对象。通常做法是:
- 定义一个继承自
URLConnection的子类(如MyProtoURLConnection) - 在自定义
URLStreamHandler的openConnection(URL u)中返回该实例 - 在连接类中重写
connect()、getInputStream()、getOutputStream(),把之前 parse 出的 host/port/path/query 传进去,用于实际通信
工厂注册必须早于任何 URL 构造
URL.setURLStreamHandlerFactory(new MyProtoFactory()) 必须在应用启动早期调用,且只能调用一次。一旦有任意 new URL("xxx://...") 先执行,Java 就会缓存默认 handler,之后再注册无效。
- 推荐放在
main方法开头,或 Spring 的ApplicationContextInitializer中 - 若用多个自定义协议,工厂的
createURLStreamHandler(String protocol)要根据 protocol 名称返回对应 handler 实例 - 注意:Android 或某些容器环境可能禁用该 API,需检查运行时权限和安全管理器限制
变量传递建议统一用 query 参数或 path segment
协议设计上,尽量避免把关键变量塞进 authority(如 myproto://user:pass@host:port),因为解析复杂且易与标准语义冲突。更稳妥的方式是:
- 用标准格式:
myproto://host:port/path?param1=value1¶m2=value2 - 或路径式:
myproto://host:port/v1/users/123?format=json,在 handler 中用正则或Paths.get()提取 - 确保
getQuery()和getPath()能稳定返回内容,后续业务代码才好复用

















