JDK中DNS缓存的分析

时间:2023-03-10 01:18:57
JDK中DNS缓存的分析

在JAVA中使用InetAddress.getByName(String host) 方法来获取给定hostname的IP地址。为了减少DNS解析的请求次数,提高解析效率,InetAddress中提供cache来缓存解析结果。

下面就此cache进行简单的分析:

该缓存实现比较简单,巧妙的利用LinkedHashMap的特性来进行过期条目的检测和移除。

    /**
* Represents a cache entry
*/
static final class CacheEntry { CacheEntry(Object address, long expiration) {
this.address = address;
this.expiration = expiration;
} Object address;
long expiration;
} //CacheEntry实例代表一个缓存记录,一个记录中包括address(IP 地址) 和 expiration /**
* A cache that manages entries based on a policy specified
* at creation time.
*/
static final class Cache {
private LinkedHashMap cache;
private Type type; enum Type {Positive, Negative};//此缓存只提供两种缓存类型 Positive: DNS解析成功 Negative:DNS解析失败 /**
* Create cache
*/
public Cache(Type type) {
this.type = type;
cache = new LinkedHashMap();//LinkedHashMap 保存了记录的插入顺序,当遍历LindedHashMap时得到的数据是最先插入的数据,此特性很重要在put方法中有所体现
} private int getPolicy() {//获取配置的缓存策略 0: 不缓存 -1: 代表永久缓存 >=1:代表缓存的时间(unit: second)
if (type == Type.Positive) {
return InetAddressCachePolicy.get();
} else {
return InetAddressCachePolicy.getNegative();
}
} /**
* Add an entry to the cache. If there's already an
* entry then for this host then the entry will be
* replaced.
*/
public Cache put(String host, Object address) {
int policy = getPolicy();
if (policy == InetAddressCachePolicy.NEVER) {
return this;
} // purge any expired entries if (policy != InetAddressCachePolicy.FOREVER) { // As we iterate in insertion order we can
// terminate when a non-expired entry is found.
LinkedList expired = new LinkedList();
Iterator i = cache.keySet().iterator();//每次put的时候都对缓存记录做一个清理,由于每个条目的过期时间是一样的,所以先插入的记录就先到期
long now = System.currentTimeMillis();
while (i.hasNext()) {
String key = (String)i.next();
CacheEntry entry = (CacheEntry)cache.get(key); if (entry.expiration >= 0 && entry.expiration < now) {
expired.add(key);
} else {
break;
}
} i = expired.iterator();
while (i.hasNext()) {
cache.remove(i.next());
}
} // create new entry and add it to the cache
// -- as a HashMap replaces existing entries we
// don't need to explicitly check if there is
// already an entry for this host.
long expiration;
if (policy == InetAddressCachePolicy.FOREVER) {
expiration = -1;
} else {
expiration = System.currentTimeMillis() + (policy * 1000);
}
CacheEntry entry = new CacheEntry(address, expiration);
cache.put(host, entry);
return this;
} /**
* Query the cache for the specific host. If found then
* return its CacheEntry, or null if not found.
*/
public CacheEntry get(String host) {
int policy = getPolicy();
if (policy == InetAddressCachePolicy.NEVER) {
return null;
}
CacheEntry entry = (CacheEntry)cache.get(host); // check if entry has expired
if (entry != null && policy != InetAddressCachePolicy.FOREVER) {//命中缓存条目后先判断是否过期
if (entry.expiration >= 0 &&
entry.expiration < System.currentTimeMillis()) {
cache.remove(host);
entry = null;
}
} return entry;
}
}