pom.xmljava
<!-- guava --> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>19.0</version> </dependency>
code sample:apache
1 package com.ctrip.arch.antibot.cepwriter.data.cache; 2 3 4 import com.ctrip.arch.antibot.cepwriter.constant.CommonConstant; 5 import com.ctrip.arch.antibot.cepwriter.data.entity.BwgResponseEntity; 6 import com.ctrip.arch.antibot.cepwriter.util.Config; 7 import com.google.common.cache.*; 8 import com.google.common.util.concurrent.ListenableFuture; 9 import com.google.common.util.concurrent.ListeningExecutorService; 10 import com.google.common.util.concurrent.MoreExecutors; 11 import org.apache.commons.lang.StringUtils; 12 import org.slf4j.Logger; 13 import org.slf4j.LoggerFactory; 14 15 import java.util.List; 16 import java.util.concurrent.Callable; 17 import java.util.concurrent.Executors; 18 import java.util.concurrent.TimeUnit; 19 20 21 public class CacheFactory { 22 private static final Logger logger = LoggerFactory.getLogger(CacheFactory.class); 23 private static class CacheFactorySingletonHolder { 24 private static final CacheFactory instance = new CacheFactory(); 25 } 26 private LoadingCache<String, BwgResponseEntity> bwgCache; 27 private long maximumSize = 100; 28 private long refreshAfterWriteSecond = 30; 29 private long expireAfterWriteMinute = 2; 30 // guava線程池,用來產生ListenableFuture 31 private ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10)); 32 33 34 35 //========= Private Constructor ========= 36 private CacheFactory(){ 37 try{ 38 init(); 39 bwgCache = buildBwgCache(); 40 }catch(Exception e){ 41 logger.error("CacheFactory(): constructor error!", e); 42 } 43 logger.info("CacheFactory(): init over ..."); 44 } 45 46 //init with config parameter 47 public void init(){ 48 Config config = Config.getInstance(); 49 String maximumSize_str = config.getParamValue(CommonConstant.CACHE_MAXIMUM_SIZE); 50 if(StringUtils.isNotBlank(maximumSize_str)){ 51 try{ 52 maximumSize = Long.parseLong(maximumSize_str); 53 }catch(Exception e){ 54 logger.error("init(): parameter '" + CommonConstant.CACHE_MAXIMUM_SIZE + "' parse error! it must be an integer."); 55 } 56 } 57 logger.info("init(): maximumSize=[" + maximumSize + "]"); 58 59 String refreshAfterWrite_str = config.getParamValue(CommonConstant.CACHE_REFRESH_AFTER_WRITE_SECOND); 60 if(StringUtils.isNotBlank(refreshAfterWrite_str)){ 61 try{ 62 refreshAfterWriteSecond = Long.parseLong(refreshAfterWrite_str); 63 }catch(Exception e){ 64 logger.error("init(): parameter '" + CommonConstant.CACHE_REFRESH_AFTER_WRITE_SECOND + "' parse error! it must be an integer."); 65 } 66 } 67 logger.info("init(): refreshAfterWriteSecond=[" + refreshAfterWriteSecond + "]"); 68 69 String expireAfterWrite_str = config.getParamValue(CommonConstant.CACHE_EXPIRE_AFTER_WRITE_MINUTE); 70 if(StringUtils.isNotBlank(expireAfterWrite_str)){ 71 try{ 72 expireAfterWriteMinute = Long.parseLong(expireAfterWrite_str); 73 }catch(Exception e){ 74 logger.error("init(): parameter '" + CommonConstant.CACHE_EXPIRE_AFTER_WRITE_MINUTE + "' parse error! it must be an integer."); 75 } 76 } 77 logger.info("init(): expireAfterWriteMinute=[" + expireAfterWriteMinute + "]"); 78 } 79 80 //Expose method 81 public static CacheFactory getInstance(){ 82 return CacheFactorySingletonHolder.instance; 83 } 84 85 //setter/getter 86 public LoadingCache<String, BwgResponseEntity> getBwgCache() { 87 return bwgCache; 88 } 89 90 91 //========= biz method ========= 92 /** 93 * LoadCache - 不須要延遲處理(泛型的方式封裝) 94 * @return 95 */ 96 private <K, V> LoadingCache<K, V> initBasicCache(CacheLoader<K, V> cacheLoader) { 97 LoadingCache<K, V> cache = CacheBuilder 98 .newBuilder() 99 .maximumSize(maximumSize) 100 .refreshAfterWrite(refreshAfterWriteSecond, TimeUnit.SECONDS) 101 .expireAfterWrite(expireAfterWriteMinute, TimeUnit.MINUTES) 102 .recordStats() //設置要統計緩存的命中率 103 .removalListener(new RemovalListener<K, V>(){ 104 @Override 105 public void onRemoval(RemovalNotification<K, V> rn) { 106 logger.debug("initBasicCache() -> onRemoval(): key=" + rn.getKey() + " is removed ..."); 107 }}) 108 .build(cacheLoader); 109 return cache; 110 } 111 112 /** 113 * 獲取 bwg cache 114 * 115 * @return bwgCache 116 * @throws Exception 117 */ 118 private LoadingCache<String, BwgResponseEntity> buildBwgCache() throws Exception { 119 LoadingCache<String, BwgResponseEntity> bwgCache = initBasicCache(new CacheLoader<String, BwgResponseEntity>(){ 120 @Override 121 public BwgResponseEntity load(String appId) throws Exception { 122 logger.debug("buildBwgCache() -> load(): load data from db, appId=" + appId); 123 BwgCallable callable = new BwgCallable(appId); 124 return (BwgResponseEntity) callable.call(); 125 } 126 127 //refresh data synchronously 128 @Override 129 public ListenableFuture<BwgResponseEntity> reload(String key, BwgResponseEntity oldValue) throws Exception { 130 logger.debug("buildBwgCache() -> reload(): ......後臺線程池異步刷新: " + key); 131 BwgCallable callable = new BwgCallable(key); 132 return service.submit(callable); 133 } 134 }); 135 return bwgCache; 136 } 137 138 139 140 }