Agile
A programmer's note
-
Hacking The Java DNS Cache - [自写]
2007-07-17
在java的程序开发中,要查找一个域名的ip,最方便的办法就是调用java.net.InetAddress.getByName("www.domain.com"),就可以得到一个IP了。InetAddress内部有一个dns解析的缓存,而在默认的情况下缓存的时间是“永久”,这个默认的行为可以通过修改java.security文件或者在启动时增加一个参数-Dsun.net.inetaddr.ttl=0 来禁止缓存,参见Disable DNS caching.
无认采取哪种方式,当jvm启动,InetAddress初始化之后,缓存策略就不能再修改了,而如果想改变策略只能是重起jvm :(
今天我做了一件我很久以前就很想做的事:在运行时动态修改DNS的缓存策略。
下面的代码是针对jdk1.5做的一个工具,通过它,可以实现DNS的缓存策略在运行时根据情况人工配置。JDK1.6的实现与1.5已经有大的差别,需要借助jad编译一个类才能知道如何做到,不过原理都是相同的。
最主要的工作就是利用“反射” 强行修改InetAddress类中的static变量addressCache:
Class clazz = java.net.InetAddress.class;
final Field cacheField = clazz.getDeclaredField("addressCache");
cacheField.setAccessible(true);
final Object o = cacheField.get(clazz);
Class clazz2 = o.getClass();
final Field cachePolicyField = clazz2.getDeclaredField("policy");
final Field cacheMapField = clazz2.getDeclaredField("cache");
cacheMapField.setAccessible(true);
final Map cacheMap = (Map)cacheMapField.get(o);
cachePolicyField.setAccessible(true);
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
try{
synchronized(o){//同步是必须的,因为o可能会有多个线程同时访问修改。cacheMap.clear();//这步比较关键,用于清除原来的缓存
cachePolicyField.setInt(o,cachePolicy);//设置缓存的时间,单位秒(-1,永久缓存;0,不缓存;其它>0的值为缓存的秒数)
}
}catch(Throwable te){
throw new RuntimeException(te);
}
return null;
}
});这个工具在使用时得先判断jvm的版本,jdk1.6的实现要复杂些,我只是简单的测试了一下,因为今天刚下载了1.6的包,测试的不多,所以这里就不列出了。
在此基础上,在服务器运行时可以手工将缓存设置为无效,当我们在程序中使用的域名变了ip之后,不用重起服务就能快速的实现ip地址切换;而当ip切换之后,又可以将缓存设置为有效,提高性能和安全性。~_~
随机文章:
HashMap.get() can cause an infinite loop! 2008-07-06Apache MINA竟然源自Netty2 2008-03-05epoll selector 2008-01-18RMI JDK6比JDK5强的地方 2008-01-03A hash set puzzler 2007-12-24
收藏到:Del.icio.us







评论
另外,jdk1.6的实现和jdk1.5差别挺大的。昨天我本以为jdk1.6应该可以做到了,结果一看它的源代码还是一样的结果,没什么大的变化,呵呵。
只能再“反射”一次~_~