您的位置:首页 > 编程语言 > Java开发

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

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

A Low Level API, which deals with the following abstractions:

Addresses, which are networking identifiers, like IP addresses.

Sockets, which are basic bidirectional data communication mechanisms.

Interfaces, which describe network interfaces.

复制代码

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

private static InetAddress[] getAllByName0 (String host, InetAddress reqAddr, boolean check)

throws UnknownHostException {

/* If it gets here it is presumed to be a hostname */

/* Cache.get can return: null, unknownAddress, or InetAddress[] */

/* make sure the connection to the host is allowed, before we

* give out a hostname

*/

if (check) {

SecurityManager security = System.getSecurityManager();

if (security != null) {

security.checkConnect(host, -1);

}

}

InetAddress[] addresses = getCachedAddresses(host);

/* If no entry in cache, then do the host lookup */

if (addresses == null) {

addresses = getAddressesFromNameService(host, reqAddr);

}

if (addresses == unknown_array)

throw new UnknownHostException(host);

return addresses.clone();

}

复制代码

关键的二个方法是:
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内部的属性:

Class<InetAddress> type = InetAddress.class;

Field[] fields = type.getDeclaredFields();

for (Field f : fields) {

System.out.println(f.getName() + ":" + f.getType());

}

复制代码

OpenJDK:

IPv4

IPv6

preferIPv6Address

holder

nameServices

canonicalHostName

serialVersionUID

addressCache

negativeCache

addressCacheInit

unknown_array

impl

lookupTable

cachedLocalHost

cacheTime

maxCacheTime

cacheLock

FIELDS_OFFSET

UNSAFE

serialPersistentFields

$assertionsDisabled

复制代码

JRockit:

IPv4

IPv6

preferIPv6Address

hostName

address

family

nameService

canonicalHostName

serialVersionUID

addressCache

negativeCache

addressCacheInit

unknown_array

impl

lookupTable

$assertionsDisabled

复制代码

IBM JDK

IPv4:int

IPv6:int

preferIPv6Address

hostName:class java.lang.String

address:int

family:int

nameService:interface sun.net.spi.nameservice.NameService

canonicalHostName:class java.lang.String

serialVersionUID:long

addressCache:class java.net.InetAddress$Cache

negativeCache:class java.net.InetAddress$Cache

localHostName:class java.lang.String

localHostNameLock:class java.lang.Object

cacheLocalHost:boolean

addressCacheInit:boolean

unknown_array:class [Ljava.net.InetAddress;

impl:interface java.net.InetAddressImpl

lookupTable:class java.util.HashMap

$assertionsDisabled:boolean

复制代码

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

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

复制代码

暂时测试到这吧, 有兴趣的同学可以一起完善. 争取同时满足OpenJDK, Jrockit, IBM JDK三种主流环境的DNS动态解析类.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: