• Java动态替换InetAddress中DNS的做法简单分析1


    在java.net包描述中, 简要说明了一些关键的接口. 其中负责networking identifiers的是Addresses. 这个类的具体实现类是InetAddress, 底层封装了Inet4Address与Inet6Address的异同, 可以看成一个Facade工具类.

    1. A Low Level API, which deals with the following abstractions:
    2.         Addresses, which are networking identifiers, like IP addresses.
    3.         Sockets, which are basic bidirectional data communication mechanisms.
    4.         Interfaces, which describe network interfaces.

    复制代码

    在OpenJDK的InetAddress源码中, 根据dns或hostname解析IP的代码部分:

    1. private static InetAddress[] getAllByName0 (String host, InetAddress reqAddr, boolean check)
    2.         throws UnknownHostException  {
    3.         /* If it gets here it is presumed to be a hostname */
    4.         /* Cache.get can return: null, unknownAddress, or InetAddress[] */
    5.         /* make sure the connection to the host is allowed, before we
    6.          * give out a hostname
    7.          */
    8.         if (check) {
    9.             SecurityManager security = System.getSecurityManager();
    10.             if (security != null) {
    11.                 security.checkConnect(host, -1);
    12.             }
    13.         }
    14.         InetAddress[] addresses = getCachedAddresses(host);
    15.         /* If no entry in cache, then do the host lookup */
    16.         if (addresses == null) {
    17.             addresses = getAddressesFromNameService(host, reqAddr);
    18.         }
    19.         if (addresses == unknown_array)
    20.             throw new UnknownHostException(host);
    21.         return addresses.clone();
    22.     }

    复制代码

    关键的二个方法是:
    getCachedAddresses(host);
    getAddressesFromNameService(host, reqAddr);
    前者从addressCache, 或negativeCache根据dns/hostname解析缓存的IP.
    后者从遍历nameServices,调用每个NameService的lookupAllHostAddr(host)查找IP, 然后将host:IP缓存到前面的cache中.
    根据上述, 实现动态解析DNS, 有二种方式:
    1. 反射addressCache, 或negativeCache, 将host:IP通过Cache的put()方法放入.
    2. 反射nameServices,将代理的NameService实例放入.
    二种做法的难处:
    1. addressCache, 或negativeCache都是 java.net.InetAddress.Cache, 其内部的CacheEntry受二组JVM选项影响:
    networkaddress.cache.ttl
    networkaddress.cache.negative.ttl
    在ttl后, CacheEntry的get()只会返回null.
    2. nameServices只是OpenJDK的实现. 换言之,只是SUN一家的. 其他JDK不用此属性名.
    写段代码看看Jrockit与IBM JVM中InetAddress内部的属性:

    1. Class<InetAddress> type = InetAddress.class;
    2.                 Field[] fields = type.getDeclaredFields();
    3.                 for (Field f : fields) {
    4.                         System.out.println(f.getName() + ":" + f.getType());
    5.                 }

    复制代码

    OpenJDK:

    1. IPv4
    2. IPv6
    3. preferIPv6Address
    4. holder
    5. nameServices
    6. canonicalHostName
    7. serialVersionUID
    8. addressCache
    9. negativeCache
    10. addressCacheInit
    11. unknown_array
    12. impl
    13. lookupTable
    14. cachedLocalHost
    15. cacheTime
    16. maxCacheTime
    17. cacheLock
    18. FIELDS_OFFSET
    19. UNSAFE
    20. serialPersistentFields
    21. $assertionsDisabled

    复制代码

    JRockit:

    1. IPv4
    2. IPv6
    3. preferIPv6Address
    4. hostName
    5. address
    6. family
    7. nameService
    8. canonicalHostName
    9. serialVersionUID
    10. addressCache
    11. negativeCache
    12. addressCacheInit
    13. unknown_array
    14. impl
    15. lookupTable
    16. $assertionsDisabled

    复制代码

    IBM JDK

    1. IPv4:int
    2. IPv6:int
    3. preferIPv6Address
    4. hostName:class java.lang.String
    5. address:int
    6. family:int
    7. nameService:interface sun.net.spi.nameservice.NameService
    8. canonicalHostName:class java.lang.String
    9. serialVersionUID:long
    10. addressCache:class java.net.InetAddress$Cache
    11. negativeCache:class java.net.InetAddress$Cache
    12. localHostName:class java.lang.String
    13. localHostNameLock:class java.lang.Object
    14. cacheLocalHost:boolean
    15. addressCacheInit:boolean
    16. unknown_array:class [Ljava.net.InetAddress;
    17. impl:interface java.net.InetAddressImpl
    18. lookupTable:class java.util.HashMap
    19. $assertionsDisabled:boolean

    复制代码

    看到这里, 知道蛋疼了吧. 三种JDK中,
    OpenJDK中是nameservices是个List<NameService>,
    Jrockit与IBM JVM中却是nameservice, 只是单独的NameService实例.
    所以要用第2种做法, 你至少要满足这三种主流JDK的需求.
    简单实现二种做法:
    做法1, 动态替换AddressCache.
    做法2, 动态代理NameService.
    源码如下

    1. 长度限制, 源码查看回贴.

    复制代码

    暂时测试到这吧, 有兴趣的同学可以一起完善. 争取同时满足OpenJDK, Jrockit, IBM JDK三种主流环境的DNS动态解析类.

  • 相关阅读:
    Redis实现分布式锁
    Redis数据结构
    Mysql与redis缓存一致性
    mysql分库分表
    mysql主从同步
    mysql配置优化
    Netty 参数优化
    JAVA多线程之park & unpack
    网络时钟服务器(网络校时服务器)无法同步的排查方法
    GPS北斗共视授时中的多径效应分析
  • 原文地址:https://www.cnblogs.com/zolo/p/5849242.html
Copyright © 2020-2023  润新知