JEP 418: 互联网地址解析 SPI
总结
定义一个用于主机名和地址解析的服务提供者接口(SPI),以便 java.net.InetAddress
可以使用除平台内置解析器之外的其他解析器。
非目标
-
本提案的目标并不是开发一个可纳入 JDK 的替代解析器。默认情况下,JDK 的内置解析器仍会继续使用。
-
本 SPI 的目标并非支持超出
InetAddress
API 所需的解析操作。 -
本提案的目标不包括定义非阻塞或异步解析 API。
动机
java.net.InetAddress
API 将主机名解析为互联网协议 (IP) 地址,反之亦然。该 API 当前使用操作系统的本地解析器,通常配置为使用本地 hosts
文件和域名系统 (DNS) 的组合。
定义名称和地址解析的服务提供者接口的动机包括:
-
Project Loom — 当前使用
InetAddress
API 的解析操作会在操作系统调用中阻塞。这对于 Loom 的用户模式虚拟线程来说是一个问题,因为它会阻止底层平台线程在等待解析操作完成时为其他虚拟线程提供服务。一个替代的解析器可以直接实现 DNS 客户端协议,而无需阻塞。 -
新兴网络协议 — 解析器 SPI 可以实现新解析协议(例如 DNS over QUIC、TLS 或 HTTPS)的无缝集成。
-
自定义 — 解析器 SPI 可以为框架和应用程序提供对解析结果的更精细控制,并允许现有库通过自定义解析器进行改造。
-
测试 — 原型设计和测试活动通常需要对主机名和地址解析结果进行控制,例如在模拟使用
InetAddress
API 的组件时。
描述
InetAddress
API 定义了多个用于查找操作的方法:
-
InetAddress::getAllByName
执行正向查询,将主机名映射到一组 IP 地址。 -
InetAddress::getByName
同样执行正向查询,将主机名映射到其地址集合中的第一个地址。 -
InetAddress::getCanonicalHostName
执行反向查询,将 IP 地址映射到完全限定域名。例如:var addressBytes = new byte[] { (byte) 192, 0, 43, 7};
var resolvedHostName = InetAddress.getByAddress(addressBytes)
.getCanonicalHostName(); -
InetAddress::getHostName
在需要时也会执行反向查询。
默认情况下,InetAddress
使用操作系统的原生解析器来执行查询。该查询的结果无论是正向还是负向的,都可能会被缓存,以避免对同一主机进行进一步的查询。
服务提供者接口
InetAddress
API 将使用 服务加载器 来定位解析器提供程序。如果未找到提供程序,则将像以前一样使用内置实现。
java.net.spi
包中的新类包括:
-
InetAddressResolverProvider
— 一个抽象类,定义了由java.util.ServiceLoader
定位的服务。InetAddressResolverProvider
本质上是一个解析器的工厂。实例化的解析器将被设置为系统范围的解析器,InetAddress
将把所有查找请求委托给该解析器。 -
InetAddressResolver
— 一个接口,定义了基本的正向和反向查找操作的方法。此接口的实例是从InetAddressResolverProvider
的实例中获取的。 -
InetAddressResolver.LookupPolicy
— 一个类,其实例描述了解析请求的特征,包括请求的地址类型以及应按何种顺序返回地址。 -
InetAddressResolverProvider.Configuration
— 一个接口,描述了平台内置的解析操作配置。它提供了对本地主机名和内置解析器的访问。自定义解析器提供者使用它来引导解析器的构建,或者将解析请求部分委托给操作系统的原生解析器。
替代方案
如果没有像这里提出的这样的 SPI,应用程序将不得不继续使用当今可用的解决方法。
-
应用程序可以使用 Java 命名和目录接口(JNDI)及其 DNS 提供程序来查找网络名称和地址。这种方法对于需要精细控制 DNS 查找的应用程序很有用,但它与
InetAddress
是分离的,因此将其与平台的网络 API 一起使用需要额外的工作。 -
应用程序可以通过 Java 本地接口(JNI)或 Project Panama 的 外部函数 API 直接使用操作系统的解析器库。然而,与 JNDI 一样,这种方法也与
InetAddress
分离,因此使用起来更加麻烦。 -
应用程序可以使用非标准的、特定于 JDK 的系统属性
jdk.net.hosts.file
来配置InetAddress
使用特定文件(而不是操作系统的原生解析器)将主机名映射到 IP 地址。此功能对于测试很有用,但由于无法提前知道完整的主机名列表,它并不是一个通用的解决方案。
测试
我们将为解析器 SPI 开发新的测试。
我们将开发概念验证的解析器提供者,以演示和验证 SPI 可用于开发和部署优先于 JDK 内置实现的替代实现。我们将至少提供其中一个提供者,以推动更完整实现的开发。