需求
监控所有的Controller Handler Method,对处理时间超过阈值的邮件报警。
实现
Spring MVC提供了interceptor的机制,可以方便的进行对handler method进行AOP。具体实现如下。
首先在Spring MVC配置文件配置一下interceptor:
<!-- Configures Handler Interceptors -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" />
<bean class="me.arganzheng.study.springmvc.interceptor.PerformanceMonitorInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
PerformanceMonitorInterceptor的实现非常简单直观:
package me.arganzheng.study.springmvc.interceptor;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import me.arganzheng.study.springmvc.Constants;
import me.arganzheng.study.springmvc.utils.WebUtils;
import em.arganzheng.study.springmvc.utils.AlarmManager;
/**
* 每个方法处理时间监控,如果超过阈值,则邮件报警。
*
* @author zhengzhibin
*
*/
public class PerformanceMonitorInterceptor extends HandlerInterceptorAdapter {
private static final Logger logger = Logger.getLogger(PerformanceMonitorInterceptor.class);
private static final long MAX_REQUEST_NEED = 10000L;
private static final int MB = 1024 * 1024;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
long startTime = System.currentTimeMillis();
request.setAttribute("startTime", startTime);
return super.preHandle(request, response, handler);
}
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod method = (HandlerMethod) handler;
long startTime = (Long) request.getAttribute("startTime");
long processTime = System.currentTimeMillis() - startTime;
if (processTime > MAX_REQUEST_NEED) {
String message = generateAlarmMessage(processTime, method, request.getRequestURI(),
request.getParameterMap());
AlarmManager.alarmEmailAsync("arganzheng@arganzheng.me",
Constants.AlarmEmail.ALARM_TITLE, Constants.AlarmEmail.SERVER_PEOLE,
message);
logger.warn("Process Timeout! " + message);
}
}
}
private String generateAlarmMessage(long processTime, HandlerMethod method, String requestUri,
Map<String, String[]> parameterMap) {
StringBuilder sb = new StringBuilder();
sb.append("RequestUri: ").append(requestUri + "\n");
sb.append("ControllerMethod: ")
.append(method.getBean().getClass().getCanonicalName() + "."
+ method.getMethod().getName());
for (Entry<String, String[]> en : parameterMap.entrySet()) {
sb.append(" ");
sb.append(en.getKey() + "=");
String[] v = en.getValue();
if (v.length > 1) {
for (String vv : v) {
sb.append(vv + ",");
}
} else {
sb.append(v[0]);
}
sb.append("\n");
}
sb.append("ProcessTime: ").append(processTime).append(" ms\n");
sb.append("LocalNetWorkIp: ").append(WebUtils.getLocalNetWorkIp() + "\n");
// Total number of processors or cores available to the JVM
sb.append("Available processors (cores): ")
.append(Runtime.getRuntime().availableProcessors()).append("\n");
long totalMemory = Runtime.getRuntime().totalMemory();
long freeMemory = Runtime.getRuntime().freeMemory();
// Total memory currently available to the JVM
sb.append("Total memory available to JVM (MB): ").append(totalMemory / MB).append("\n");
// used memory
sb.append("Used Memory (MBs): ").append((totalMemory - freeMemory) / MB).append("\n");
// Total amount of free memory available to the JVM
sb.append("Free memory (MBs): ").append(freeMemory / MB).append("\n");
// Maximum amount of memory the JVM will attempt to use
sb.append("Maximum memory (MBs): ").append(Runtime.getRuntime().maxMemory() / MB)
.append("\n");
return sb.toString();
}
}