LoadingCache<String,T> cacheLoader= CacheBuilder .newBuilder() .expireAfterWrite(5, TimeUnit.MINUTES) .build(new CacheLoader<String, T>() { @Override public T load(String key) throws Exception { return method(key);//1.執行method,獲取key對應的值 } });
使用的方法:java
T value=cacheLoader.get(key);//獲取key對應的值
public abstract class RefreshKeepCacheLoader<K, V> extends CacheLoader<K, V> { public ListenableFuture<V> reload(K key, V oldValue) throws Exception { Object newvalue = null; try { newvalue = this.load(key); } catch (Exception e) { } if(newvalue == null) { newvalue = oldValue; } return Futures.immediateFuture(newvalue); } }
那麼此時咱們的cacheLoader能夠這麼寫:git
LoadingCache<String,T> cacheLoader= CacheBuilder .newBuilder() .expireAfterWrite(5, TimeUnit.MINUTES) .build(new RefreshKeepCacheLoader<String, T>() { @Override public T load(String key) throws Exception { return method(key);//2.執行method,獲取key對應的值 } });
與上面不一樣的是,用自定義的RefreshKeepCacheLoader替換了CacheLoader類,因爲緩存過時會執行reload方法,若是reload異常,就採用oldValue。github
public ListenableFuture<V> reload(K key, V oldValue) throws Exception { checkNotNull(key); checkNotNull(oldValue); return Futures.immediateFuture(load(key)); }
其實經過方法名,就能夠看出執行load方法,而後用Futures.immediateFuture封裝成ListenableFuture,再來看下immediateFuture方法web
/** * Creates a {@code ListenableFuture} which has its value set immediately upon construction. The * getters just return the value. This {@code Future} can't be canceled or timed out and its * {@code isDone()} method always returns {@code true}. */ public static <V> ListenableFuture<V> immediateFuture(@Nullable V value) { if (value == null) { // This cast is safe because null is assignable to V for all V (i.e. it is covariant) @SuppressWarnings({"unchecked", "rawtypes"}) ListenableFuture<V> typedNull = (ListenableFuture) ImmediateSuccessfulFuture.NULL; return typedNull; } return new ImmediateSuccessfulFuture<V>(value); }
這就比較清楚了,這個future中直接設置的是值。
那麼咱們如今就要重寫這個reload方法。ajax
public abstract class RefreshAsyncCacheLoader<K, V> extends CacheLoader<K, V> { @Override public ListenableFuture<V> reload(final K key, final V oldValue) throws Exception { ListenableFutureTask<V> task = ListenableFutureTask.create(new Callable<V>() { public V call() { try { return load((K) key); } catch (Exception e) { } return oldValue; } }); ThreadPoolUtil.getInstance().execute(task);//這裏將這個task放到自定義的線程池中去執行,返回一個futrue,能夠經過future獲取線程執行獲取的值 return task; } }
LoadingCache<String,T> cacheLoader= CacheBuilder .newBuilder() .expireAfterWrite(5, TimeUnit.MINUTES) .build(new RefreshAsyncCacheLoader <String, T>() { @Override public T load(String key) throws Exception { return method(key);//1.執行method,獲取key對應的值 } });
下面咱們作一個簡單的實驗,涉及到WebController,CacheTest這兩個類。spring
package com.netease.mail.activity.web.controller; import com.netease.mail.activity.constant.RetCode; import com.netease.mail.activity.meta.RequestHolder; import com.netease.mail.activity.meta.vo.common.AjaxResult; import com.netease.mail.activity.service.CacheTest; import com.netease.mail.rambo.log.StatLogger; import com.netease.mail.rambo.log.StatLoggerFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.http.HttpServletRequest; /** * 重構web-control * Created by hzlaojiaqi on 2016/9/19. */ @Controller public class WebController { private static final Logger INTERACTIVE_LOG = LoggerFactory.getLogger("INTERACTIVE_LOGGER"); public static final StatLogger USER_TRACE_LOG = StatLoggerFactory.getLogger("emptyProject"); @Autowired RequestHolder mRequestHolder; @Autowired CacheTest cacheTest; /** * 獲取當前uid的信息 * @param httpServletRequest * @return */ @RequestMapping(value = "/ajax/getActInfo.do",method = RequestMethod.GET) @ResponseBody public AjaxResult getActInfo2(HttpServletRequest httpServletRequest){ String uid = mRequestHolder.getUid(); return new AjaxResult(RetCode.SUCCESS,cacheTest.cacheGet(uid)); } }
package com.netease.mail.activity.service; import com.netease.mail.activity.cache.RedisConfigure; import com.netease.mail.activity.web.controller.BaseAjaxController; import com.netease.mail.util.common.TimeUtil; import net.sf.ehcache.Cache; import net.sf.ehcache.CacheManager; import net.sf.ehcache.Element; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; /** * Created by hzlaojiaqi on 2017/11/9. */ @Service public class CacheTest extends BaseService{ @Cacheable(cacheManager = "activityCacheManager",key = "'actCache_'+#uid",cacheNames = "actCache",unless = "#result==null") public String cacheGet(String uid){ String s = uid + "_" + TimeUtil.now(); THIRDPARTY_LOG.info("cacheGet in method uid:{} s:{}",uid,s); return s; } }
LoadingCache<String,Object> cache = CacheBuilder .newBuilder() .maximumSize(5210) .refreshAfterWrite(10, TimeUnit.SECONDS) .build(new RefreshAsyncCacheLoader<String, Object>() { @Override public Object load(String key) throws Exception { Object o = mRedis.opsForValue().get(key); THIRDPARTY_LOG.debug("thread:{},activityManager local cache reload key:{},result:{}",Thread.currentThread().getName(),key,o); return o; } });
Ps:文章不免有紕漏,望拍磚指正,感謝。編程