• 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切换之后,又可以将缓存设置为有效,提高性能和安全性。~_~

     


    收藏到:Del.icio.us




    评论

  • sfd
  • 很好,你的无私奉献精神可佳.
  • 真不错!我也很想做这个的....
    agilejava回复曹晓钢说:
    呵呵,我也是迫不得已,因为公司的应用遇到这个问题了,但又不能总是重起服务.
    另外,jdk1.6的实现和jdk1.5差别挺大的。昨天我本以为jdk1.6应该可以做到了,结果一看它的源代码还是一样的结果,没什么大的变化,呵呵。
    只能再“反射”一次~_~
    2007-07-17 10:16:35

发表评论

您将收到博主的回复邮件
记住我