需求:对请求次数、最大请求时间、请求时间总和等数据进行监控(参照durid uri监控)
实现方案:aop切面+自定义注解方式实现
自定义注解类:
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface AroundLog{
String flag() default "";
int count() default 1;
}
Aspect切面类:(这里用的是若依的RedisCache缓存类 如果不是用的若依框架的话换成redis也一样)
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.lzqf.annotation.AroundLog;
import com.ruoyi.lzqf.domain.vo.InterfaceListenVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.StopWatch;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Aspect
@Slf4j
@Component
public class AroundLogAspect {
@Autowired
private RedisCache redisCache;
@Around("@annotation(aroundLog)")
public Object aroundLog(ProceedingJoinPoint point, AroundLog aroundLog) {
List<InterfaceListenVo> list = new ArrayList<>();
List<String> nameList = new ArrayList<>();
StringBuilder sb = new StringBuilder();
StopWatch started = new StopWatch();
try {
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
sb.append("\n<===================================START===================================>\n");
sb.append("call time:>").append(LocalDateTime.now()).append("\n");
String methodName = method.getName();
sb.append("method name:> ").append(methodName).append("\n");
sb.append("log flag:> ").append(aroundLog.flag()).append("\n");
started.start();
Object proceed = point.proceed();
return proceed;
} catch (RuntimeException e) {
sb.append("RuntimeException:>").append(e.getMessage()).append("\n");
throw e;
} catch (Throwable throwable) {
sb.append("Throwable:>").append(throwable.getMessage()).append("\n");
throw new RuntimeException("系统异常!");
} finally {
started.stop();
sb.append("call total time(ms) :> ").append(started.getTime()).append("\n");
sb.append("<====================================END====================================>\n");
List<InterfaceListenVo> arrayList = new ArrayList<>();
List<InterfaceListenVo> interfaceListen = redisCache.getCacheList("interfaceListen");
if (interfaceListen.size() == 0) {
InterfaceListenVo vo = new InterfaceListenVo();
vo.setCount(aroundLog.count());
vo.setInterfaceName(aroundLog.flag());
vo.setRequestMaxTime(started.getTime());
vo.setRequestTimeSum(started.getTime());
//将vo对象放入集合中
list.add(vo);
redisCache.setCacheList("interfaceListen", list);
}
//如果interfaceListen集合中不为空 则遍历集合 将集合中的元素取出
if (interfaceListen.size() >= 1) {
interfaceListen.forEach(vo -> list.add(vo));
interfaceListen.forEach(vo -> nameList.add(vo.getInterfaceName()));
}
redisCache.deleteObject("interfaceListen");
//如果 当前正在执行的接口 接口名不在nameList集合中
if(!nameList.contains(aroundLog.flag())){
//则创建新的vo对象 将该对象放入arrayList集合中
InterfaceListenVo vo1 = new InterfaceListenVo();
vo1.setCount(aroundLog.count());
vo1.setInterfaceName(aroundLog.flag());
vo1.setRequestMaxTime(started.getTime());
vo1.setRequestTimeSum(started.getTime());
arrayList.add(vo1);
}
//将redis中的vo对象取出放入list集合中
list.stream().forEach(vo -> {
//如果 当前正在执行的接口 接口名在nameList集合中 并且当前正在执行的接口 接口名与正在遍历的vo对象名一样
if (nameList.contains(aroundLog.flag()) && vo.getInterfaceName().equals(aroundLog.flag())){
//修改当前vo对象的值
vo.setCount(vo.getCount() + aroundLog.count());
vo.setRequestTimeSum(vo.getRequestTimeSum() + started.getTime());
vo.setRequestMaxTime(vo.getRequestMaxTime() > started.getTime() ? vo.getRequestMaxTime() : started.getTime());
arrayList.add(vo);
return;
}
arrayList.add(vo);
});
redisCache.setCacheList("interfaceListen",arrayList);
log.info(sb.toString());
}
}
}
vo类:
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class InterfaceListenVo {
/**
* 接口名
*/
private String interfaceName;
/**
* 请求时间总和
*/
private Long requestTimeSum;
/**
* 请求次数
*/
private int count;
/**
* 请求时间最大值
*/
private Long requestMaxTime;
}
使用:在你自己项目中的业务接口上加上@AroundLog(flag = "/flow/processes/export",count = 1)即可
@AroundLog(flag = "/flow/processes/export",count = 1)
@PreAuthorize("@ss.hasPermi('flow:processes:export')")
@Log(title = "流程定义", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, LzqfBpmnInfo lzqfBpmnInfo)
{
List<LzqfBpmnInfo> list = lzqfBpmnInfoService.selectLzqfBpmnInfoList(lzqfBpmnInfo);
ExcelUtil<LzqfBpmnInfo> util = new ExcelUtil<LzqfBpmnInfo>(LzqfBpmnInfo.class);
util.exportExcel(response, list, "流程定义明细数据");
}
controller层接口:
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.redis.RedisCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/interface/listen")
public class InterfaceListenController {
@Autowired
private RedisCache redisCache;
@Anonymous
@GetMapping("/info")
public AjaxResult queryInterfaceListenInfo(){
return AjaxResult.success(redisCache.getCacheList("interfaceListen"));
}
}
效果: