JEP 418: Internet-Address Resolution SPI | Internet 地址解析 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 地址映射到完全限定的域名。例如:javavar 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 内置实现的替代实现。我们将至少提供一个这样的提供者,以促进更完整实现的开发。