Skip to content

Latest commit

 

History

History
 
 

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 

README.md

Java Dns Cache Manipulator(DCM) Library

Build Status Windows Build Status Coverage Status
Maven Central GitHub release Dependency Status
GitHub issues License

👉 通过代码直接设置JavaDNS(实际上设置的是DNS Cache),支持JDK 6+,支持IPv6

🔧 功能

  • 设置/重置DNS(不会再去Lookup DNS
    • 可以设置单条
    • 或是通过Properties文件批量设置
  • 清空DNS Cache(即所有的域名重新Lookup DNS
  • 删除一条DNS Cache(即重新Lookup DNS
  • 查看DNS Cache内容
  • 修改/查看JVM缺省的DNS的缓存时间

🎨 需求场景

  1. 一些库中写死了连接域名,需要通过修改host文件绑定才能做测试。结果是:
    • 自动持续集成的机器上一般同学是没有权限去修改host文件的,导致项目不能持续集成。
      实际上是因为这点,催生这个库的需求。 😣🔫
    • 单元测试需要每个开发都在开发机上做host绑定,增加了依赖的配置操作且繁琐重复。
  2. 一些功能需要域名作为输入参数,如使用HTTP请求的网关 或是 有域名检查限制的Web应用。
    这种情况下,让需要让一个域名连接到测试机器的IP上,或是 使用一个还不存在的域名但又不想或不能去配置DNS
  3. 在性能测试时,
    • 不去做网络的DNS LookupDNS解析消耗),这样使得压测更加关注服务器响应,压测更充分反应出实现代码的性能。
    • 可以动态修改DNS缓存,无需修改host文件和http链接等不灵活的方式。
    • 一个JVM进程可以对应一套域名绑定,相互之间不影响,可以实现多场景,多域名绑定的需求压测。
  4. 打开Java中的SecurityManager时(如在Web容器Tomcat中的Web应用),JavaDNS缺省是不会失效的。 如果域名绑定的IP变了,可以通过这个库重置DNS,作为一个临时的手段(强烈不推荐)。
    • 通过Java Dns Cache Manipulator Tool修改运行中JVM DNS Cache
      无需应用包含了Java Dns Cache Manipulator Library依赖(即Jar)。
    • 或通过执行入口调用Java Dns Cache Manipulator Library的方法,比如远程调用或是jvm-ssh-groovy-shell
      需要应用已经包含了Java Dns Cache Manipulator Library依赖(即Jar)。

👥 User Guide

通过类DnsCacheManipulator设置DNS

直接设置

DnsCacheManipulator.setDnsCache("www.hello.com", "192.168.1.1");
DnsCacheManipulator.setDnsCache("www.world.com", "1234:5678:0:0:0:0:0:200e"); // 支持IPv6地址

// 之后Java代码中使用到域名都会解析成上面指定的IP。
// 下面是一个简单获取域名对应的IP,演示一下:

String ip = InetAddress.getByName("www.hello.com").getHostAddress();
// ip = "192.168.1.1"
String ipv6 = InetAddress.getByName("www.world.com").getHostAddress();
// ipv6 = "1234:5678:0:0:0:0:0:200e"

通过dns-cache.properties文件批量配置

在代码测试中,会期望把域名绑定写在配置文件。

使用方式如下:

ClassPath上,提供文件dns-cache.properties

# 配置格式:
# <host> = <ip>
www.hello-world.com=192.168.1.1
www.foo.com=192.168.1.2

然后通过下面的一行代码完成批量设置:

DnsCacheManipulator.loadDnsCacheConfig();

在单元测试中,往往会写在测试类的setUp方法中,如:

@BeforeClass
public static void beforeClass() throws Exception {
    DnsCacheManipulator.loadDnsCacheConfig();
}

清空JVM DNS Cache

DnsCacheManipulator.clearDnsCache();

删除一条DNS Cache

即重新Lookup DNS

DnsCacheManipulator.removeDnsCache("baidu.com");

查看JVM DNS Cache

DnsCache dnsCache = DnsCacheManipulator.getWholeDnsCache()
System.out.println(dnsCache);

修改/查看JVM缺省的DNS的缓存时间

// 查看缓存时间,单位秒。-1表示永远缓存,0表示不缓存
int cachePolicy = DnsCacheManipulator.getDnsCachePolicy();
// 设置缓存时间
DnsCacheManipulator.setDnsCachePolicy(2);

// 查看未命中条目的缓存时间
DnsCacheManipulator.getDnsNegativeCachePolicy()
// 设置未命中条目的缓存时间
DnsCacheManipulator.setDnsNegativeCachePolicy(0);

使用注意

  • 域名不区分大小写,域名会统一转成小写,再进入DNS Cache
    其中一个引发的现象是,DNS查询结果的域名会和输入的域名大小写不同,如果输入的域名有大写字母。
  • 对于已经完成解析保存了IP的逻辑,修改JVM DNS缓存,不会生效!可以重新创建 连接或Client解决。
    如对于HttpClient:
HttpClient client = new HttpClient();
GetMethod m1 = new GetMethod("http://www.baidu.com");
client.executeMethod(m1);
String content = m1.getResponseBodyAsString();

// 修改DNS,绑定到自己的机器
DnsCacheManipulator.setDnsCache("www.baidu.com", "192.168.1.1");

// 重新执行m1,仍然是老结果
client.executeMethod(m1);
String content = m1.getResponseBodyAsString();

// 重新创建GetMethod,才能得到自己机器上的结果
GetMethod m2 = new GetMethod("http://www.baidu.com");
client.executeMethod(m2);
content = m2.getResponseBodyAsString();

更多详细功能

参见类DnsCacheManipulator的文档说明。

经过测试的JDK

JDK 系统 On 备注
openjdk6 64-Bit Linux travis-ci
oraclejdk7 64-Bit Linux travis-ci
openjdk7 64-Bit Linux travis-ci
oraclejdk8 64-Bit Linux travis-ci
applejdk6 64-Bit Mac 个人Mac jdk6及以下,Apple提供了自己的Java版本
oraclejdk7 64-Bit Mac 个人Mac 从jdk7开始,Mac jdk直接在Oracle下载。
oraclejdk8 64-Bit Mac 个人Mac
oraclejdk7 64-Bit windows server 2012 r2 appveyor
oraclejdk7 32-Bit windows server 2012 r2 appveyor
oraclejdk8 64-Bit windows server 2012 r2 appveyor
oraclejdk8 32-Bit windows server 2012 r2 appveyor

PS:
感谢 travis-ciappveyor 免费提供了持续集成环境。

🔌 Java API Docs

Java API文档地址: http://alibaba.github.io/java-dns-cache-manipulator/apidocs

🍪 依赖

Maven示例:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>dns-cache-manipulator</artifactId>
    <version>1.5.0</version>
</dependency>

可以在search.maven.org查看最新的版本。

🎓 Developer Guide

如何修改JVMDNS Cache

JVMDNS Cache维护在类InetAddressaddressCache私有字段中,通过反射来修改, 具体参见InetAddressCacheUtil

注意修改JVMDNS Cache的线程安全问题

JVMDNS 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块,以保证线程安全。

需要测试不同版本JDK

本库实现使用了JDK的非公开API,不同JDK实现会不一样,即需要有兼容逻辑,并对不同版本JDK进行测试,以保证功能。

目前测试包含JDK版本参见【经过测试的JDK】一节。

📚 相关资料