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动态解析类.
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动态解析类.
相关文章推荐
- Java动态替换InetAddress中DNS的做法简单分析2
- org.apache.harmony.tests.java.net.InetAddressTest#test_isReachableLjava_net_NetworkInterfaceII 分析
- 利用JAVA的动态属性之反射原理实现一个简单AOP容器 - AOP的实现原理分析
- java静态代理与动态代理简单分析
- java静态代理与动态代理简单分析
- Java动态代理分析及简单实例
- java静态代理与动态代理简单分析
- java.util.Arrays.sort方法简单分析
- 简单理解java.lang.IllegalStateException异常:简单分析和简单解决方案
- 把一个java web应用包装成桌面应用的简单做法(网摘)
- (Java2D 学习笔记系列) (一)一个简单的图像填充实例及其分析理解
- Java动态显示文件上传进度的简单实现
- Java动态编译一个简单的例子(我转载的,但是经过修定,可以在Eclipse下运行)
- 把一个java web应用包装成桌面应用的简单做法(转)
- Java动态代理机制分析
- Java 动态代理机制分析及扩展,第 1 部分
- JAVA中String替换性能简单测试
- java动态代理的简单实现:
- Java程序开发中的简单内存分析
- 简单理解java.lang.IllegalStateException异常:简单分析和简单解决方案