文章转载于:https://blog.csdn.net/goldenfish1919/article/details/78094090
已经重写了,代码在这:https://github.com/xjs1919/ezprofiler,主要使用以下方式实现:
(1)通过实现BeanPostProcessor,做Controller扫描
(2)通过EnableProfiler这个注解,加载内部的Controller
(3)通过自定义HandlerMapping,添加对内部Controller的访问
使用起来很简单,只需要2步:
(1)添加依赖:
-
<dependency>
-
<groupId>com.github.xjs </groupId>
-
<artifactId>ezprofiler-spring-boot-starter </artifactId>
-
<version>0.0.1-SNAPSHOT </version>
-
</dependency>
(2)引入配置类打开ezprofiler:
-
-
-
public class EzProfilerConfigure {
-
-
}
(3)自定义一些参数,可以省略
-
ezprofiler.basepackage=com.test //设置controller所在的包
-
ezprofiler.enableBasic=true//启用basic认证
-
ezprofiler.username=xjs
-
ezprofiler.password=123456
-
#ezprofiler.url=/my/profiler//接口的url
打开浏览器访问就ok了!
---------------------------以下是第一版-------------------------------
背景:
有时候为了对系统进行优化,我们需要找出系统中访问时间长的那些方法,本文就来演示下,如何实现这个功能。最终实现的效果是访问一个url,列出当前系统中所有api接口的访问信息,包括:接口的调用次数、正常调用次数、异常调用次数、接口的平均访问时间、最大访问时间、最小访问时间,如图所示:
思路:
(1)定义一个拦截器,记录方法的开始时间和结束时间
(2)定义一个全局的异常处理器,记录防范访问发生异常
(3)定义ThreadLocal,保存方法的访问信息。
(4)为了访问多线程并发访问影响记录的准确性,用队列把计算串行化。
(5)定义结果输出界面
下面基于SpringBoot来实现一下。
(1)定义拦截器
-
-
public class AccessInterceptor implements HandlerInterceptor {
-
-
-
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
-
if(handler instanceof HandlerMethod){
-
HandlerMethod hm = (HandlerMethod)handler;
-
AccessInfo mi = new AccessInfo();
-
mi.setHm(hm);
-
mi.setStartAt(System.currentTimeMillis());
-
mi.setUri(request.getRequestURI());
-
AccessHolder.accessStart(mi); //记录方法开始
-
}
-
return true;
-
}
-
-
-
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView model)
-
throws Exception {
-
//可以向view中写入数据
-
}
-
-
-
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception)
-
throws Exception {
-
if(handler instanceof HandlerMethod){
-
AccessHolder.accessEnd(); //记录方法结束
-
}
-
}
-
}
(2)定义异常处理器
-
-
-
public class GlobalExceptionHandler {
-
-
public Result<String> allExceptionHandler(HttpServletRequest request, Exception exception) throws Exception{
-
AccessHolder.accessError(); //记录方法异常
-
if(exception instanceof BizException){
-
exception.printStackTrace();
-
BizException biz = (BizException)exception;
-
return Result.error(biz.getCodeMsg());
-
} else {
-
exception.printStackTrace();
-
return Result.error(CodeMsg.SERVER_ERROR);
-
}
-
}
-
}
(3)定义ThreadLocal
-
-
public class AccessHolder {
-
-
private static ThreadLocal<AccessInfo> accessHolder = new ThreadLocal<AccessInfo>(); //记录单次访问信息
-
-
private static ConcurrentHashMap<Class<?>, ControllerAccessInfo> map = new ConcurrentHashMap<Class<?>, ControllerAccessInfo>(); //记录所有的访问信息
-
-
private static WorkingService<AccessRequest> workingService = new WorkingService<AccessRequest>(); //工作队列,串行化
-
-
static {
-
workingService.start();
-
}
-
-
public static void accessStart(AccessInfo mai) {
-
accessHolder.set(mai);
-
}
-
-
public static AccessInfo getAccessInfo() {
-
return accessHolder.get();
-
}
-
-
public static void accessError() {
-
AccessInfo ai = getAccessInfo() ;
-
if(ai == null) {
-
return;
-
}
-
ai.setOccurError( true);
-
}
-
-
public static void accessEnd() {
-
AccessInfo ai = getAccessInfo();
-
if(ai == null) {
-
return;
-
}
-
ai.setEndAt(System.currentTimeMillis());
-
accessHolder.set( null);
-
workingService.execute( new AccessRequest(ai), new LazyExecutable<AccessRequest>() {
-
-
public void lazyExecute(AccessRequest request) {
-
addAccessInfo(request.getAi());
-
}
-
});
-
}
-
-
private static void addAccessInfo(AccessInfo ai) {
-
HandlerMethod hm = ai.getHm();
-
Class<?> controllerClazz = hm.getBeanType();
-
if(!AccessAble.class.isAssignableFrom(controllerClazz)) {
-
return;
-
}
-
Method method = hm.getMethod();
-
long startAt = ai.getStartAt();
-
long endAt = ai.getEndAt();
-
boolean occurError = ai.isOccurError();
-
long useTime = endAt - startAt;
-
String uri = ai.getUri();
-
ControllerAccessInfo cai = map.get(controllerClazz);
-
if(cai == null) {
-
cai = new ControllerAccessInfo();
-
cai.setControllerClazz(controllerClazz);
-
map.put(controllerClazz, cai);
-
}
-
List<MethodAccessInfo> mais = cai.getMethodInfos();
-
if(mais == null) {
-
mais = new ArrayList<MethodAccessInfo>();
-
cai.setMethodInfos(mais);
-
}
-
MethodAccessInfo mai = getMethodAccessInfo(mais, method);
-
if(mai == null) {
-
mai = new MethodAccessInfo();
-
mai.setMethod(method.getName());
-
mai.setUri(uri);
-
mai.setInvokeCount( 1);
-
if(occurError) {
-
mai.setErrorCount( 1);
-
} else {
-
mai.setSuccessCount( 1);
-
}
-
mai.setMinMillSecond(useTime);
-
mai.setMaxMillSecond(useTime);
-
mai.setAvgMillSecond(useTime);
-
mais.add(mai);
-
} else {
-
if(useTime < mai.getMinMillSecond()) {
-
mai.setMinMillSecond(useTime);
-
}
-
if(useTime > mai.getMaxMillSecond()) {
-
mai.setMaxMillSecond(useTime);
-
}
-
mai.setInvokeCount(mai.getInvokeCount() + 1);
-
if(occurError) {
-
mai.setErrorCount(mai.getErrorCount()+ 1);
-
} else {
-
mai.setSuccessCount(mai.getSuccessCount()+ 1);
-
}
-
mai.setAvgMillSecond((mai.getAvgMillSecond()+useTime)/ 2);
-
}
-
}
-
-
private static MethodAccessInfo getMethodAccessInfo(List<MethodAccessInfo> mais, Method method) {
-
for(MethodAccessInfo mai : mais) {
-
if(method.getName().equals(mai.getMethod())) {
-
return mai;
-
}
-
}
-
return null;
-
}
-
-
public static Map<String, Object> getAllAccessInfo() {
-
Map<String, Object> result = new HashMap<String, Object>();
-
for(Map.Entry<Class<?>, ControllerAccessInfo> entry : map.entrySet()) {
-
ControllerAccessInfo cai = entry.getValue();
-
result.put(cai.getControllerClazz().getSimpleName(), cai.getMethodInfos());
-
}
-
return result;
-
}
-
}
(4)利用SpringBoot的EndPoint把结果输出出去
-
public class AccessEndPoint implements Endpoint<Map<String, Object>> {
-
-
public String getId() {
-
return "access";
-
}
-
-
public boolean isEnabled() {
-
return true;
-
}
-
-
public boolean isSensitive() {
-
return false;
-
}
-
-
public Map<String, Object> invoke() {
-
return AccessHolder.getAllAccessInfo();
-
}
-
}
-
-
public class EndPointAutoConfig {
-
-
public AccessEndPoint myEndPoint() {
-
return new AccessEndPoint();
-
}
-
}