77import com .jarvis .cache .to .CacheKeyTO ;
88import com .jarvis .cache .to .CacheWrapper ;
99import lombok .extern .slf4j .Slf4j ;
10+ import org .apache .commons .lang3 .StringUtils ;
1011
1112import java .lang .reflect .Method ;
1213import java .util .Arrays ;
13- import java .util .concurrent . ConcurrentHashMap ;
14- import java .util .concurrent . LinkedBlockingQueue ;
15- import java .util .concurrent .ThreadLocalRandom ;
14+ import java .util .Timer ;
15+ import java .util .TimerTask ;
16+ import java .util .concurrent .* ;
1617
1718/**
1819 * 用于处理自动加载缓存,sortThread 从autoLoadMap中取出数据,然后通知threads进行处理。
@@ -60,6 +61,13 @@ public class AutoLoadHandler {
6061 */
6162 private final AutoLoadConfig config ;
6263
64+
65+ private static ScheduledThreadPoolExecutor scheduledThreadPoolExecutor ;
66+
67+ public static ScheduledThreadPoolExecutor getScheduledThreadPoolExecutor () {
68+ return scheduledThreadPoolExecutor ;
69+ }
70+
6371 /**
6472 * @param cacheHandler 缓存的set,get方法实现类
6573 * @param config 配置
@@ -75,6 +83,8 @@ public AutoLoadHandler(CacheHandler cacheHandler, AutoLoadConfig config) {
7583 this .sortThread = new Thread (new SortRunnable ());
7684 this .sortThread .setDaemon (true );
7785 this .sortThread .start ();
86+ // init fixed rate refresh process thread pool
87+ initScheduledThreadPoolExecutor ();
7888 for (int i = 0 ; i < this .config .getThreadCnt (); i ++) {
7989 this .threads [i ] = new Thread (new AutoLoadRunnable ());
8090 this .threads [i ].setName (THREAD_NAME_PREFIX + i );
@@ -89,6 +99,10 @@ public AutoLoadHandler(CacheHandler cacheHandler, AutoLoadConfig config) {
8999 }
90100 }
91101
102+ private void initScheduledThreadPoolExecutor () {
103+ scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor (10 );
104+ }
105+
92106 public int getSize () {
93107 if (null != autoLoadMap ) {
94108 return autoLoadMap .size ();
@@ -146,6 +160,29 @@ public AutoLoadTO putIfAbsent(CacheKeyTO cacheKey, CacheAopProxyChain joinPoint,
146160 if (null == autoLoadMap ) {
147161 return null ;
148162 }
163+
164+ // 如果fixRateUpdateCache注解字段不为空,则走固定刷新逻辑
165+ if (StringUtils .isNotEmpty (cache .fixRateUpdateCache ())) {
166+ AutoLoadTO autoLoadTO = autoLoadMap .get (cacheKey );
167+ if (null != autoLoadTO ) {
168+ autoLoadMap .remove (cacheKey );
169+ }
170+
171+ DeepClone deepClone = new DeepClone (joinPoint , cache ).invoke ();
172+ if (deepClone .is ()) return null ;
173+
174+ Object [] arguments = deepClone .getArguments ();
175+ autoLoadTO = new AutoLoadTO (cacheKey , joinPoint , arguments , cache , Integer .MAX_VALUE );
176+ // 设置过期时间为永不过期
177+ autoLoadTO .setExpire (Integer .MAX_VALUE );
178+
179+ boolean openFixRateUpdateCache = fixRateUpdateCacheIfNeeded (joinPoint .getMethod ().getName (), autoLoadTO );
180+ if (openFixRateUpdateCache ) {
181+ return null ;
182+ }
183+ }
184+
185+ // 走老逻辑-》交由AutoLoad处理
149186 AutoLoadTO autoLoadTO = autoLoadMap .get (cacheKey );
150187 if (null != autoLoadTO ) {
151188 return autoLoadTO ;
@@ -185,6 +222,120 @@ public AutoLoadTO putIfAbsent(CacheKeyTO cacheKey, CacheAopProxyChain joinPoint,
185222 return null ;
186223 }
187224
225+ private boolean fixRateUpdateCacheIfNeeded (String methodName , AutoLoadTO autoLoadTO ) {
226+ if (null == autoLoadTO || autoLoadTO .getCache () == null ||
227+ StringUtils .isEmpty (autoLoadTO .getCache ().fixRateUpdateCache ())) {
228+ return false ;
229+ }
230+
231+ // 如果配置固定频率刷新 则缓存有效期为永久
232+ doExecute (methodName , autoLoadTO );
233+ return true ;
234+ }
235+
236+ private void doExecute (String methodName , AutoLoadTO autoLoadTO ) {
237+ // 解析fixRateUpdateCache Timer表达式
238+ String updateCacheCronExpression = autoLoadTO .getCache ().fixRateUpdateCache ();
239+ if (!updateCacheCronExpression .contains ("," )) {
240+ log .error ("不符合规则的频率表达式{}" , updateCacheCronExpression );
241+ return ;
242+ }
243+ long delay ;
244+ long period ;
245+ try {
246+ String [] split = updateCacheCronExpression .split ("," );
247+ delay = Long .parseLong (split [0 ]);
248+ period = Long .parseLong (split [1 ]);
249+ } catch (Exception e ) {
250+ log .error ("not matched cron expression-{}" , updateCacheCronExpression );
251+ return ;
252+ }
253+ scheduledThreadPoolExecutor .scheduleWithFixedDelay (new FixRateUpdateCacheTask (autoLoadTO ), delay ,
254+ period , TimeUnit .SECONDS );
255+ log .info ("register fix rate refresh task——method-{}, rate-{}" , methodName , updateCacheCronExpression );
256+ }
257+
258+ class FixRateUpdateCacheTask implements Runnable {
259+ private AutoLoadTO autoLoadTO ;
260+
261+ public FixRateUpdateCacheTask (AutoLoadTO autoLoadTO ) {
262+ this .autoLoadTO = autoLoadTO ;
263+ }
264+
265+ @ Override
266+ public void run () {
267+ // 执行更新 依然复用"拿来主义"
268+ Cache cache = autoLoadTO .getCache ();
269+ log .debug ("执行定时刷新缓存任务, {}" , cache .fixRateUpdateCache ());
270+ CacheWrapper <Object > result = null ;
271+ if (config .isCheckFromCacheBeforeLoad ()) {
272+ try {
273+ Method method = autoLoadTO .getJoinPoint ().getMethod ();
274+ result = cacheHandler .get (autoLoadTO .getCacheKey (), method );
275+ } catch (Exception ex ) {
276+ log .error (ex .getMessage (), ex );
277+ }
278+
279+ if (null != result ) {
280+ autoLoadTO .setExpire (result .getExpire ());
281+ if (result .getLastLoadTime () > autoLoadTO .getLastLoadTime ()) {
282+ autoLoadTO .setLastLoadTime (result .getLastLoadTime ());
283+ return ;
284+ }
285+ }
286+ }
287+ CacheAopProxyChain pjp = autoLoadTO .getJoinPoint ();
288+ CacheKeyTO cacheKey = autoLoadTO .getCacheKey ();
289+ DataLoader dataLoader ;
290+ if (config .isDataLoaderPooled ()) {
291+ DataLoaderFactory factory = DataLoaderFactory .getInstance ();
292+ dataLoader = factory .getDataLoader ();
293+ } else {
294+ dataLoader = new DataLoader ();
295+ }
296+ CacheWrapper <Object > newCacheWrapper = null ;
297+ long loadDataUseTime = 0L ;
298+ try {
299+ newCacheWrapper = dataLoader .init (pjp , autoLoadTO , cacheKey , cache , cacheHandler ).loadData ()
300+ .getCacheWrapper ();
301+ loadDataUseTime = dataLoader .getLoadDataUseTime ();
302+ } catch (Throwable e ) {
303+ log .error (e .getMessage (), e );
304+ } finally {
305+ if (config .isDataLoaderPooled ()) {
306+ DataLoaderFactory factory = DataLoaderFactory .getInstance ();
307+ factory .returnObject (dataLoader );
308+ }
309+ }
310+ // 如果数据加载失败,则把旧数据进行续租
311+ if (null == newCacheWrapper && null != result ) {
312+ newCacheWrapper = new CacheWrapper <Object >(result .getCacheObject (), Integer .MAX_VALUE );
313+ }
314+ writeCacheAndSetLoadTime (cache , pjp , cacheKey , newCacheWrapper , loadDataUseTime , autoLoadTO );
315+ }
316+ }
317+
318+ /**
319+ * 写入缓存并且设置上一次加载时间
320+ * @param cache
321+ * @param pjp
322+ * @param cacheKey
323+ * @param newCacheWrapper
324+ * @param loadDataUseTime
325+ * @param autoLoadTO
326+ */
327+ private void writeCacheAndSetLoadTime (Cache cache , CacheAopProxyChain pjp , CacheKeyTO cacheKey , CacheWrapper <Object > newCacheWrapper , long loadDataUseTime , AutoLoadTO autoLoadTO ) {
328+ try {
329+ if (null != newCacheWrapper ) {
330+ cacheHandler .writeCache (pjp , autoLoadTO .getArgs (), cache , cacheKey , newCacheWrapper );
331+ autoLoadTO .setLastLoadTime (newCacheWrapper .getLastLoadTime ())
332+ .setExpire (newCacheWrapper .getExpire ()).addUseTotalTime (loadDataUseTime );
333+ }
334+ } catch (Exception e ) {
335+ log .error (e .getMessage (), e );
336+ }
337+ }
338+
188339 /**
189340 * 获取自动加载队列,如果是web应用,建议把自动加载队列中的数据都输出到页面中,并增加一些管理功能。
190341 *
@@ -252,7 +403,6 @@ public void run() {
252403 }
253404
254405 class AutoLoadRunnable implements Runnable {
255-
256406 @ Override
257407 public void run () {
258408 while (running ) {
@@ -372,17 +522,46 @@ private void loadCache(AutoLoadTO autoLoadTO) {
372522 int newExpire = AUTO_LOAD_MIN_EXPIRE + 60 ;
373523 newCacheWrapper = new CacheWrapper <Object >(result .getCacheObject (), newExpire );
374524 }
525+ writeCacheAndSetLoadTime (cache , pjp , cacheKey , newCacheWrapper , loadDataUseTime , autoLoadTO );
526+ }
527+ }
528+ }
529+
530+ private class DeepClone {
531+ private boolean myResult ;
532+ private CacheAopProxyChain joinPoint ;
533+ private Cache cache ;
534+ private Object [] arguments ;
535+
536+ public DeepClone (CacheAopProxyChain joinPoint , Cache cache ) {
537+ this .joinPoint = joinPoint ;
538+ this .cache = cache ;
539+ }
540+
541+ boolean is () {
542+ return myResult ;
543+ }
544+
545+ public Object [] getArguments () {
546+ return arguments ;
547+ }
548+
549+ public DeepClone invoke () {
550+ if (cache .argumentsDeepcloneEnable ()) {
375551 try {
376- if (null != newCacheWrapper ) {
377- cacheHandler .writeCache (pjp , autoLoadTO .getArgs (), cache , cacheKey , newCacheWrapper );
378- autoLoadTO .setLastLoadTime (newCacheWrapper .getLastLoadTime ())
379- .setExpire (newCacheWrapper .getExpire ()).addUseTotalTime (loadDataUseTime );
380- }
552+ // 进行深度复制
553+ arguments = (Object []) cacheHandler .getCloner ().deepCloneMethodArgs (joinPoint .getMethod (),
554+ joinPoint .getArgs ());
381555 } catch (Exception e ) {
382556 log .error (e .getMessage (), e );
557+ myResult = true ;
558+ return this ;
383559 }
560+ } else {
561+ arguments = joinPoint .getArgs ();
384562 }
563+ myResult = false ;
564+ return this ;
385565 }
386566 }
387-
388567}
0 commit comments