如何在简单的 Java Web 代理中实现内部 DNS 缓存



我的目标是在代理中实现内部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();
    }
}

最新更新