我的目标是在代理中实现内部DNS缓存:基本上是为了保存我的DNS解析以备将来使用,在您需要之前,请检查缓存中是否有所需的解析。为简单起见,我忽略了 TTL,而是使用默认值最多 30 秒。我将如何去做这样的事情,即使是指向正确方向的指针也会不胜感激?我的 Java Web 代理看起来与 http://www.jtmelton.com/2007/11/27/a-simple-multi-threaded-java-http-proxy-server/示例中的代理非常相似。
您是否知道 Java 已经具有缓存 DNS 请求的机制?
看看:
networkaddress.cache.ttl
networkaddress.cache.negative.ttl
源
这是我为解决这个问题而编写的两个类
DnsCache
import java.net.InetAddress;
/**
* Singleton class that holds the ExpiringMap used for DNS Cache
*/
public class DnsCache {
private static ExpiringMap<String, InetAddress> theDnsCache = null;
public static ExpiringMap<String, InetAddress> getInstance() {
if (theDnsCache == null) {
theDnsCache = new ExpiringMap<String, InetAddress>();
}
return theDnsCache;
}
}
即将到期的地图
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
* A HashMap that removes objects after the set TTL
*/
public class ExpiringMap<K, V> implements Map<K, V> {
private final int DEFAULT_TTL = 30;
private final HashMap<K, ScheduledFuture<K>> cacheKeys = new HashMap<K, ScheduledFuture<K>>();
private final HashMap<K, V> theHash = new HashMap<K, V>();
private ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
@Override
public int size() {
// TODO Auto-generated method stub
return theHash.size();
}
@Override
public boolean isEmpty() {
return theHash.isEmpty();
}
@Override
public boolean containsKey(Object key) {
return theHash.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return theHash.containsValue(value);
}
/**
* If retrieving an object that already exists in the cache
* we must resets the TTL timer on that item.
*/
@SuppressWarnings("unchecked")
@Override
public V get(final Object key) {
// If item exists in cache, then we cancel and reset the timer on that item
if(cacheKeys.containsKey(key) && cacheKeys.get(key).cancel(false)) {
ScheduledFuture<K> task = executorService.schedule(new Callable<K>() {
@Override
public K call() {
cacheKeys.remove(key);
theHash.remove(key);
return (K) key;
}
}, DEFAULT_TTL, TimeUnit.SECONDS);
cacheKeys.put((K) key, task);
}
return theHash.get(key);
}
/**
* When we add an item to cache we add the key to a map that contains FutureScheduled
* events that will remove the item after TTL
*/
@Override
public V put(final K key, V value) {
ScheduledFuture<K> task = executorService.schedule(new Callable<K>() {
@Override
public K call() {
cacheKeys.remove(key);
theHash.remove(key);
return key;
}
}, DEFAULT_TTL, TimeUnit.SECONDS);
cacheKeys.put(key, task);
return theHash.put(key, value);
}
@Override
public V remove(Object key) {
cacheKeys.remove(key);
return theHash.remove(key);
}
@Override
public void putAll(Map<? extends K, ? extends V> m) {
// TODO implement
}
@Override
public void clear() {
cacheKeys.clear();
theHash.clear();
}
@Override
public Set<K> keySet() {
return theHash.keySet();
}
@Override
public Collection<V> values() {
return theHash.values();
}
@Override
public Set<java.util.Map.Entry<K, V>> entrySet() {
return theHash.entrySet();
}
}