import java.io.IOException;
import java.lang.ref.SoftReference;
import java.net.URI;
import java.security.cert.CRLException;
import java.security.cert.CertificateException;
import java.security.cert.X509CRL;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.naming.NamingException;
import org.joda.time.DateTime;
import org.kp.oppr.esb.logger.Logger;
import org.springframework.beans.factory.annotation.Autowired;
public class CachedCrlRepository {
private static final Logger LOGGER = new Logger("CachedCrlRepository");
private final Map<URI, SoftReference<X509CRL>> crlCache = Collections
.synchronizedMap(new HashMap<URI, SoftReference<X509CRL>>());;
private static int DEFAULT_CACHE_AGING_HOURS;
@Autowired
private DgtlSgntrValidator validator;
@Autowired
private CrlRepository crlRepository;
public X509CRL findCrl(URI crlUri, X509Certificate issuerCertificate,
Date validationDate) throws DigitalValdiationException,
CertificateException, CRLException, IOException, NamingException {
SoftReference<X509CRL> crlRef = this.crlCache.get(crlUri);
if (null == crlRef) {
LOGGER.info("Key CRL URI : " + crlUri + " not found in the cache ");
return refreshCrl(crlUri, issuerCertificate, validationDate);
}
X509CRL crl = crlRef.get();
if (null == crl) {
LOGGER.info("CRL Entry garbage collected: " + crlUri);
return refreshCrl(crlUri, issuerCertificate, validationDate);
}
if (validationDate.after(crl.getNextUpdate())) {
LOGGER.info("CRL URI no longer valid: " + crlUri);
LOGGER.info("CRL validation date: " + validationDate + " is after CRL next update date: " + crl.getNextUpdate());
return refreshCrl(crlUri, issuerCertificate, validationDate);
}
Date thisUpdate = crl.getThisUpdate();
LOGGER.info("This update " + thisUpdate);
/*
* The PKI the nextUpdate CRL extension indicates 7 days. The
* actual CRL refresh rate is every 3 hours. So it's a bit dangerous to
* only base the CRL cache refresh strategy on the nextUpdate field as
* indicated by the CRL.
*/
DateTime cacheMaturityDateTime = new DateTime(thisUpdate)
.plusHours(DEFAULT_CACHE_AGING_HOURS);
LOGGER.info("Cache maturity Date Time " + cacheMaturityDateTime);
if (validationDate.after(cacheMaturityDateTime.toDate())) {
LOGGER.info("Validation date: " + validationDate + " is after cache maturity date: " + cacheMaturityDateTime.toDate());
return refreshCrl(crlUri, issuerCertificate, validationDate);
}
LOGGER.info("using cached CRL: " + crlUri);
return crl;
}
public static int getDEFAULT_CACHE_AGING_HOURS() {
return DEFAULT_CACHE_AGING_HOURS;
}
public static void setDEFAULT_CACHE_AGING_HOURS(int dEFAULT_CACHE_AGING_HOURS) {
DEFAULT_CACHE_AGING_HOURS = dEFAULT_CACHE_AGING_HOURS;
}
private X509CRL refreshCrl(URI crlUri, X509Certificate issuerCertificate,
Date validationDate) throws DigitalValdiationException,
CertificateException, CRLException, IOException, NamingException {
X509CRL crl = crlRepository.downloadCRL(crlUri.toString());
this.crlCache.put(crlUri, new SoftReference<X509CRL>(crl));
return crl;
}
}
我有這個類CachedCrlrepository存儲來自特定提供者的CRL列表。我想知道我的實現是線程安全的還是我在這裏丟失了某些東西。緩存用於Web服務,因此它是多線程的。線程內存緩存的安全實現
我在這個特殊的方法
private X509CRL refreshCrl(URI crlUri, X509Certificate issuerCertificate,
Date validationDate) throws DigitalValdiationException,
CertificateException, CRLException, IOException, NamingException {
X509CRL crl = crlRepository.downloadCRL(crlUri.toString());
this.crlCache.put(crlUri, new SoftReference<X509CRL>(crl));
return crl;
}
我覺得這一行需要同步
this.crlCache.put(crlUri, new SoftReference<X509CRL>(crl));
synchronized(this)
{
this.crlCache.put(crlUri, new SoftReference<X509CRL>(crl));
}
另外一個問題,我看到的是,一個GC運行緩存後仍然有疑問內存中的條目。它從來沒有執行這些行代碼
if (null == crl) {
LOGGER.info("CRL Entry garbage collected: " + crlUri);
return refreshCrl(crlUri, issuerCertificate, validationDate);
}
我真的很困惑,你想讓它線程安全嗎? –
請考慮使用類似[Caffeine](https://github.com/ben-manes/caffeine/wiki/Cache)的庫。 –
Re。 'put()':不,對'Collections.synchronizedMap()'的調用爲你做。我不喜歡使用'SoftReference',這不是一個好習慣。 – markspace