👉 通过代码直接设置Java
的DNS
(实际上设置的是DNS Cache
),支持JDK 6+
。
- 设置/重置
DNS
(不会再去Lookup DNS
)- 可以设置单条
- 或是通过
Properties
文件批量设置
- 查看
DNS Cache
内容 - 删除一条
DNS Cache
(即重新Lookup DNS
) - 清空
DNS Cache
(即所有的域名重新Lookup DNS
)
- 一些库中写死了连接域名,需要通过修改
host
文件绑定才能做测试。结果是:- 自动持续集成的机器上一般同学是没有权限去修改
host
文件的,导致项目不能持续集成。
实际上是因为这点,催生这个库的需求。 😣🔫 - 单元测试需要每个开发都在开发机上做
host
绑定,增加了依赖的配置操作且繁琐重复。
- 自动持续集成的机器上一般同学是没有权限去修改
- 一些功能需要域名作为输入参数,如使用
HTTP
请求的网关 或是 有域名检查限制的Web
应用。
这种情况下,让需要让一个域名连接到测试机器的IP
上,或是 使用一个还不存在的域名但又不想或不能去配置DNS
。 - 在性能测试时,
- 不去做网络的
DNS Lookup
(DNS
解析消耗),这样使得压测更加关注服务器响应,压测更充分反应出实现代码的性能。 - 可以动态修改
DNS
缓存,无需修改host
文件和http
链接等不灵活的方式。 - 一个
JVM
进程可以对应一套域名绑定,相互之间不影响,可以实现多场景,多域名绑定的需求压测。
- 不去做网络的
- 打开
Java
中的SecurityManager
时(如在Web
容器Tomcat
中的Web
应用),Java
的DNS
缺省是不会失效的。 如果域名绑定的IP
变了,可以通过这个库重置DNS
,作为一个临时的手段(强烈不推荐)。
当然往往进行要先有能执行入口,比如远程调用或是jvm-ssh-groovy-shell
。
通过类DnsCacheManipulator
设置DNS
。
DnsCacheManipulator.setDnsCache("www.hello-world.com", "192.168.10.113");
// 之后Java代码中使用到域名都会解析成上面指定的IP。
// 下面是一个简单获取域名对应的IP,演示一下:
String ip = InetAddress.getByName("www.hello-world.com").getHostAddress();
// ip = "192.168.10.113"
在代码测试中,会期望把域名绑定写在配置文件。
使用方式如下:
在ClassPath
上,提供文件dns-cache.properties
:
# 配置格式:
# <host> = <ip>
www.hello-world.com=192.168.10.113
www.foo.com=192.168.10.2
然后通过下面的一行代码完成批量设置:
DnsCacheManipulator.loadDnsCacheConfig();
在单元测试中,往往会写在测试类的setUp
方法中,如:
@BeforeClass
public static void beforeClass() throws Exception {
DnsCacheManipulator.loadDnsCacheConfig();
}
DnsCacheManipulator.clearDnsCache();
DnsCache dnsCache = DnsCacheManipulator.getWholeDnsCache()
System.out.println(dnsCache);
更多详细功能参见类DnsCacheManipulator
的文档说明。
Java API
文档地址: http://alibaba.github.io/java-dns-cache-manipulator/apidocs
Maven
示例:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dns-cache-manipulator</artifactId>
<version>1.2.0</version>
</dependency>
可以在search.maven.org查看可用的版本。
JVM
的DNS Cache
维护在类InetAddress
的addressCache
私有字段中,通过反射来修改,
具体参见InetAddressCacheUtil
。
JVM
的DNS Cache
显然是全局共用的,所以修改需要同步以保证没有并发问题。
通过查看类InetAddress
的实现可以确定:通过以addressCache
字段为锁的synchronized
块来保证线程安全。
其中关键代码(JDK 7
)如下:
/*
* Cache the given hostname and addresses.
*/
private static void cacheAddresses(String hostname,
InetAddress[] addresses,
boolean success) {
hostname = hostname.toLowerCase();
synchronized (addressCache) {
cacheInitIfNeeded();
if (success) {
addressCache.put(hostname, addresses);
} else {
negativeCache.put(hostname, addresses);
}
}
}
InetAddressCacheUtil
类中对DNS Cache
的读写也一致地加了以addressCache
为锁的synchronized
块,以保证线程安全。
- tanhaichao的
javahost
项目, 该项目的使用文档。
本项目如何设置Java DNS Cache
的解法来自该项目。刚开始在持续集成项目中碰到host
绑定的问题时,也是使用该项目来解决的 👍 - 类
InetAddress
的源代码:JDK 6
的InetAddress
JDK 7
的InetAddress
JDK 8
的InetAddress
JVM Networking Properties
-java docs
java dns
解析缓存之源码解析,写得很完整,源码解析。给出值得注意的结论:- 打开
Java
中的SecurityManager
,DNS
缓存将不会生效。 - 否则,可访问的
DNS
解析缺省缓存30秒,不可访问的DNS
解析缺省缓存10秒。
- 打开
- 关于
jvm dns cache
(域名缓存时间),给出“对于多条A记录是采用什么策略返回IP
”的结论:- 在缓存有效期内,取到的
IP
永远是缓存中全部A记录的第一条,并没有轮循之类的策略。 - 缓存失效之后重新进行DNS解析,因为每次域名解析返回的A记录顺序会发生变化(
dig www.google.com
测试可见),所以缓存中的数据顺序也变了,取到的IP
也变化。
- 在缓存有效期内,取到的
- 通过
JAVA
反射修改JDK 1.6
当中DNS
缓存内容,给出了修改DNS
缓存在性能测试下使用的场景。 - Domain Name System - wikipedia
Java DNS
FAQ