1.自定义注解
package com.gzz.common.aop;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @类说明 [配合AOP统计时长的自定义注解类]
* @author 高振中
* @date 2019-11-26
**/
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface CountTime {
String app() default "";// 当前应用名
String method() default "";// 当前方法名
Class<?> clazz();// 当前类
}
2.切面类
package com.gzz.common.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
/**
* @类说明 [方法时长统计切面程序]
* @author 高振中
* @date 2019-11-26
**/
@Slf4j
@Aspect
@Component
public class CountTimeAop {
@Around("within(com.gzz..*) && @annotation(countTime) ")
public Object ChangeRobotAops(ProceedingJoinPoint point, CountTime countTime) {
Object proceed = null;
String path = null;
try {
Long start = System.currentTimeMillis();
proceed = point.proceed();// 调用目标方法
path = countTime.clazz().getName() + "." + countTime.method();
log.info("应用名:{},类名.方法名:{}(),耗时:{}毫秒", countTime.app(), path, System.currentTimeMillis() - start);
} catch (Throwable e) {
log.error("获取{" + path + "}方法消耗时长时发生异常!", e);
}
return proceed;
}
}
3.使用
/**
* @方法说明:新增用户记录
**/
@CountTime(app = "plat", clazz = UserController.class, method = "save")
@PostMapping("save")
public int save(@RequestBody User user) {
return service.save(user);
}
4.最终将数据落地,存入数据库
package com.xsrt.plat.servercompute;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.stream.Collectors;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.xsrt.beans.servercompute.ServerCompute;
import com.xsrt.common.base.Page;
/**
* @author 高振中
* @类说明 [服务管理]业务逻辑层
* @date 2018-11-13 16:46:47
**/
@Service
public class ServerComputeService {
protected final Log logger = LogFactory.getLog(ServerComputeService.class);// 日志类
private Map<String, ServerCompute> serverComputeCache = Maps.newHashMap();
private ConcurrentLinkedQueue<ServerCompute> pushTaskQueue = new ConcurrentLinkedQueue<>();
@Autowired
private ServerComputeDao dao; // 注入服务管理数据访问层
/**
* @方法说明 按条件查询分页服务管理列表
*/
public Page<ServerCompute> queryPage(ServerComputeCond cond) {
return dao.queryPage(cond);
}
/**
* @方法说明 请求进队列
*/
public void add(ServerCompute serverCompute) {
pushTaskQueue.offer(serverCompute);
}
/**
* @方法说明 每隔50毫秒 取一个值进缓存
*/
@Scheduled(fixedDelay = 50)
private void putToCahce() {
if (!this.pushTaskQueue.isEmpty()) {
ServerCompute serverCompute = this.pushTaskQueue.poll();
String key = serverCompute.getApp_name() + "_" + serverCompute.getServer_path();
ServerCompute old = getOld(serverCompute, key);
// 计算方法
serverCompute.setSum_millisecond(old.getSum_millisecond() + serverCompute.getCurrent_millisecond());
serverCompute.setMax_millisecond(Math.max(serverCompute.getCurrent_millisecond(), old.getMax_millisecond()));
serverCompute.setMin_millisecond(Math.min(serverCompute.getCurrent_millisecond(), old.getMin_millisecond()));
serverCompute.setSum_count(old.getSum_count() + 1);
serverCompute.setAvg_millisecond((float) serverCompute.getSum_millisecond() / serverCompute.getSum_count());
serverCompute.setCanSave(true);
serverComputeCache.put(key, serverCompute);
}
}
/**
* @方法说明 取前一次的值
*/
private ServerCompute getOld(ServerCompute serverCompute, String key) {
ServerCompute old = serverComputeCache.get(key);
if (old != null)
return old;
ServerComputeCond computeCond = ServerComputeCond.builder().server_path(serverCompute.getServer_path()).app_name(serverCompute.getApp_name()).build();
List<ServerCompute> list = this.dao.queryList(computeCond);
if (!list.isEmpty()) // 数据库中不存在的情况
return list.get(0);
old = new ServerCompute();
old.setApp_name(serverCompute.getApp_name());
old.setServer_path(serverCompute.getServer_path());
return old;
}
/**
* @方法说明 每隔30秒 入库一次
*/
@Scheduled(fixedDelay = 30000)
private void run() {
List<ServerCompute> saveList = this.serverComputeCache.values().stream().filter(ServerCompute::isCanSave).collect(Collectors.toList());
if (!saveList.isEmpty()) {
Lists.partition(saveList, 500).forEach(this.dao::insertBatch);
saveList.forEach(serverCompute -> serverCompute.setCanSave(false));
}
}
}
5.建表语句
CREATE TABLE `admin_server_compute` (
`server_path` varchar(200) NOT NULL COMMENT '接口路径',
`app_name` varchar(20) NOT NULL COMMENT '应用名',
`sum_count` bigint(20) DEFAULT NULL COMMENT '请求次数',
`sum_millisecond` bigint(20) DEFAULT NULL COMMENT '请求总时长',
`avg_millisecond` decimal(12,2) DEFAULT NULL COMMENT '请求平均时长',
`max_millisecond` int(11) DEFAULT NULL COMMENT '请求最大时长',
`min_millisecond` int(11) DEFAULT NULL COMMENT '请求最小时长',
PRIMARY KEY (`server_path`,`app_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
网友评论