日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

counter计数器

發布時間:2023/12/18 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 counter计数器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、為什么要做計數器:

在唯品會的工作的時候,為了更好的推動系統向智慧供應鏈發展,理性分析供應商和商助對產品的使用頻率,追溯服務歷史調用情況,于是,開發了一款輕量級計數器,供各團隊使用。

二、難點:

1、調用量大

2、各團隊需要保證極端情況下,計數器服務不可用時,不影響各團隊業務正常運行

3、需要使用簡單

4、個別需要統一業務日志

5、不能有額外的定時器一直輪詢

三、優勢:

1、簡單? ?@LogCounter? 對應的類或者方法上 即可開啟計數器功能

2、可配置? ? 日志記錄可選擇開啟和關閉、可選擇記錄到本地、可選擇記錄到遠程服務器

3、統一日志? 開啟日志功能后,即可對方法的入參和出參進行記錄

4、采用了線程池隔離

5、設計了漏斗策略

四、代碼:

? ? ??https://gitee.com/sunrisexq/counter

? ? ??

package com.javaxiaobang.counter.aspect.log;import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/*** 功 能:日志注解標簽* 作 者:java瀟邦* 時 間:2018-05-19*/ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Documented public @interface LogCounter {String counterName() default "";//計數器名稱boolean useLogFile() default true;//true時記錄log日志boolean useRemote() default true;//true時記錄counterboolean useLocal() default false;//true時開啟本地counter} package com.javaxiaobang.counter.aspect.log;import com.alibaba.fastjson.JSON; import com.javaxiaobang.counter.exception.CounterException; import org.apache.commons.lang3.StringUtils; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component;import java.lang.reflect.Method; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;/*** 功 能:日志AOP* 作 者:java瀟邦* 時 間:2018-05-19*/ @Order @Aspect @Component("commonLogCounterAop") public class LogCounterAop {private final Logger logger = LoggerFactory.getLogger(this.getClass());private static ExecutorService pool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());@Autowiredprivate LogCounterLocalBusiness logCounterLocalBusiness;@Autowiredprivate LogCounterRemoteBusiness logCounterRemoteBusiness;//切入點@Pointcut("@annotation(com.javaxiaobang.counter.aspect.log.LogCounter)")public void anyMethod() {}//方法執行之前@Before("anyMethod()")public void before(final JoinPoint joinPoint) {try {Signature signature = joinPoint.getSignature();MethodSignature methodSignature = (MethodSignature) signature;Method method = methodSignature.getMethod();if (method != null && method.isAnnotationPresent(LogCounter.class)) {String methodName = method.getName();final LogCounter aspect = method.getAnnotation(LogCounter.class);if (aspect.useLogFile()) {logger.info("{}{}方法的參數值:{}", aspect.counterName(), methodName, JSON.toJSONString(joinPoint.getArgs()));}final String counterName = StringUtils.isBlank(aspect.counterName()) ? methodName : aspect.counterName();if (aspect.useLocal()) {pool.submit(new Runnable() {@Overridepublic void run() {logCounterLocalBusiness.execute(counterName);}});}if (aspect.useRemote()) {pool.submit(new Runnable() {@Overridepublic void run() {logCounterRemoteBusiness.execute(counterName);}});}}} catch (Exception e) {logger.debug("before切面異常:", e);}}//方法執行之后@AfterReturning(pointcut = "anyMethod()", returning = "retVal")public void after(JoinPoint joinPoint, Object retVal) {try {Signature signature = joinPoint.getSignature();MethodSignature methodSignature = (MethodSignature) signature;Method method = methodSignature.getMethod();if (method != null) {String methodName = method.getName();LogCounter aspect = method.getAnnotation(LogCounter.class);if (aspect != null && aspect.useLogFile()) {logger.info("{}{}方法的返回值:{}", aspect.counterName(), methodName, JSON.toJSONString(retVal));}}} catch (Exception e) {logger.debug("after切面異常:", e);}}//方法執行之后異常日志@AfterThrowing(pointcut = "anyMethod()", throwing = "e")public void afterThrowing(JoinPoint joinPoint, Throwable e) throws CounterException {//不需要再記錄ServiceException,因為在service異常切面中已經記錄過if (e instanceof CounterException) {throw (CounterException) e;} else {Signature signature = joinPoint.getSignature();MethodSignature methodSignature = (MethodSignature) signature;Method method = methodSignature.getMethod();if (method != null) {String methodName = method.getName();LogCounter aspect = method.getAnnotation(LogCounter.class);logger.warn("{}{}方法異常:", aspect.counterName(), methodName, e);throw new CounterException();}}}} package com.javaxiaobang.counter.aspect.log;import com.javaxiaobang.counter.util.LogCounterUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component;import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.ReentrantLock;/*** 功 能:遠程計數器-調用遠程服務保存數據* 作 者:java瀟邦* 時 間:2018-05-19*/ @Component("logCounterRemoteBusiness") public class LogCounterRemoteBusiness {private final Logger logger = LoggerFactory.getLogger(this.getClass());private static ReentrantLock lock = new ReentrantLock();private static String domain = LogCounterUtil.getDomain();private static long tryLockTime = 2;//嘗試2秒獲取鎖的時間private static long refreshTime = 30000L;//30秒刷新一次private static ConcurrentHashMap<String, AtomicLong> countMap = new ConcurrentHashMap<String, AtomicLong>(32);//并發計數private static ConcurrentHashMap<String, Long> timeMap = new ConcurrentHashMap<String, Long>(32);//并發計時private static long detailRefreshTime = 10 * 60 * 1000L;//默認10分鐘刷新數據private static ConcurrentHashMap<String, AtomicLong> detailCountMap = new ConcurrentHashMap<String, AtomicLong>(32);//并發計數private static ConcurrentHashMap<String, Long> detailTimeMap = new ConcurrentHashMap<String, Long>(32);//并發計時// private CounterServiceHelper.CounterServiceClient client = new CounterServiceHelper.CounterServiceClient();//唯品會counter服務-對應兩張表/*** 計數器邏輯處理*/public void execute(String counterName) {commonMethod("total", counterName, refreshTime, countMap, timeMap);//計數器頭表commonMethod("detail", counterName, detailRefreshTime, detailCountMap, detailTimeMap);//計數器明細表}private void commonMethod(String type, String counterName, long refreshTime, ConcurrentHashMap<String, AtomicLong> countMap, ConcurrentHashMap<String, Long> timeMap) {try {String key = counterName + domain;//唯一keyAtomicLong atomicLong = countMap.get(key);if (null == atomicLong) {//原子計數器synchronized (lock) {//并發控制atomicLong = countMap.get(key);if (null == atomicLong) {countMap.put(key, new AtomicLong(1));timeMap.put(key, System.currentTimeMillis());return;}}}atomicLong.incrementAndGet();//原子計數器加1boolean flag = (System.currentTimeMillis() - timeMap.get(key) > refreshTime) && (atomicLong.get() > 0);//超過N秒 并且 次數大于0if (flag) {//滿足條件的漏斗if (lock.tryLock(tryLockTime, TimeUnit.SECONDS)) {try {flag = (System.currentTimeMillis() - timeMap.get(key) > refreshTime) && (atomicLong.get() > 0);//避免錯誤更新if (flag) {long counter = countMap.get(key).get();timeMap.put(key, System.currentTimeMillis());//重新計時atomicLong.set(0);countMap.put(key, atomicLong);//重新計數if ("detail".equals(type)) {incrementDetailCounter(counterName, domain, counter, refreshTime);} else {incrementCounter(counterName, domain, counter);}}} finally {lock.unlock();}} else {logger.warn("2秒內沒有獲取到鎖則放棄,下次再調用遠程保存數據的服務:{}", key);}}} catch (Exception e) {logger.debug("remote計數器異常:", e);}}/*** 保存到counter_info頭表*/public void incrementCounter(String counterName, String domain, long counter) {//調用遠程方法 // try { // CounterInfo counterInfo = new CounterInfo(); // counterInfo.setCounterName(counterName); // counterInfo.setDomain(domain); // counterInfo.setCounter(counter); // client.incrementCounter(counterInfo); // } catch (Exception e) { // logger.debug("incrementCounter:", e); // }}/*** 保存到counter_detail明細表*/public void incrementDetailCounter(String counterName, String domain, long counter, long interval) {//調用遠程方法 // try { // CounterInfo counterInfo = new CounterInfo(); // counterInfo.setCounterName(counterName); // counterInfo.setDomain(domain); // counterInfo.setCounter(counter); // counterInfo.setInterval(interval); // client.incrementDetailCounter(counterInfo); // } catch (Exception e) { // logger.debug("incrementDetailCounter:", e); // }}public static long getRefreshTime() {return refreshTime;}public static void setRefreshTime(long refreshTime) {LogCounterRemoteBusiness.refreshTime = refreshTime;}public static long getDetailRefreshTime() {return detailRefreshTime;}public static void setDetailRefreshTime(long detailRefreshTime) {LogCounterRemoteBusiness.detailRefreshTime = detailRefreshTime;}public static void setDomain(String domain) {LogCounterRemoteBusiness.domain = domain;}public static String getDomain() {return domain;}} package com.javaxiaobang.counter.aspect.log;import com.javaxiaobang.counter.aspect.delay.LogCounterDelayInterface; import com.javaxiaobang.counter.util.LogCounterUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.ReentrantLock;/*** 功 能:本地計數器-實現LogCounterDelayInterface接口-保存到本地數據庫* 作 者:java瀟邦* 時 間:2018-05-19*/ @Component("logCounterLocalBusiness") public class LogCounterLocalBusiness {private final Logger logger = LoggerFactory.getLogger(this.getClass());private static ReentrantLock lock = new ReentrantLock();private static String domain = LogCounterUtil.getDomain();private static long tryLockTime = 2;//嘗試2秒獲取鎖的時間private static long refreshTime = 30000L;//30秒刷新一次private static ConcurrentHashMap<String, AtomicLong> countMap = new ConcurrentHashMap<String, AtomicLong>(32);//并發計數private static ConcurrentHashMap<String, Long> timeMap = new ConcurrentHashMap<String, Long>(32);//并發計時private static long detailRefreshTime = 10 * 60 * 1000L;//默認10分鐘刷新數據private static ConcurrentHashMap<String, AtomicLong> detailCountMap = new ConcurrentHashMap<String, AtomicLong>(32);//并發計數private static ConcurrentHashMap<String, Long> detailTimeMap = new ConcurrentHashMap<String, Long>(32);//并發計時//懶加載@Autowired(required = false)private LogCounterDelayInterface logCounterDelayInterface;/*** 計數器邏輯處理*/public void execute(String counterName) {commonMethod("total", counterName, refreshTime, countMap, timeMap);commonMethod("detail", counterName, detailRefreshTime, detailCountMap, detailTimeMap);}private void commonMethod(String type, String counterName, long refreshTime, ConcurrentHashMap<String, AtomicLong> countMap, ConcurrentHashMap<String, Long> timeMap) {try {String key = counterName + domain;//唯一keyAtomicLong atomicLong = countMap.get(key);if (null == atomicLong) {//原子計數器synchronized (lock) {//并發控制atomicLong = countMap.get(key);if (null == atomicLong) {countMap.put(key, new AtomicLong(1));timeMap.put(key, System.currentTimeMillis());return;}}}atomicLong.incrementAndGet();//原子計數器加1boolean flag = (System.currentTimeMillis() - timeMap.get(key) > refreshTime) && (atomicLong.get() > 0);//超過N秒 并且 次數大于0if (flag) {//滿足條件的漏斗if (lock.tryLock(tryLockTime, TimeUnit.SECONDS)) {try {flag = (System.currentTimeMillis() - timeMap.get(key) > refreshTime) && (atomicLong.get() > 0);//避免錯誤更新if (flag) {long counter = countMap.get(key).get();timeMap.put(key, System.currentTimeMillis());//重新計時atomicLong.set(0);countMap.put(key, atomicLong);//重新計數if ("detail".equals(type)) {logCounterDelayInterface.incrementDetailCounter(counterName, domain, counter, refreshTime);} else {logCounterDelayInterface.incrementCounter(counterName, domain, counter);}}} finally {lock.unlock();}} else {logger.warn("2秒內沒有獲取到鎖則放棄,下次再調用保存數據的服務:{}", key);}}} catch (Exception e) {logger.info("local計數器異常:", e);}}public static void setDomain(String domain) {LogCounterLocalBusiness.domain = domain;}public static String getDomain() {return domain;}public static long getRefreshTime() {return refreshTime;}public static void setRefreshTime(long refreshTime) {LogCounterLocalBusiness.refreshTime = refreshTime;}public static long getDetailRefreshTime() {return detailRefreshTime;}public static void setDetailRefreshTime(long detailRefreshTime) {LogCounterLocalBusiness.detailRefreshTime = detailRefreshTime;} }

?

總結

以上是生活随笔為你收集整理的counter计数器的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。