Spring MVC afterCompletion方法详解
afterCompletion是HandlerInterceptor接口的三个核心方法之一,在视图渲染完成后执行,用于资源清理和日志记录。
方法定义
Java
void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception;
执行时机
Java
请求到达
↓
preHandle() → 返回true继续
↓
Controller处理
↓
postHandle() → 视图渲染前
↓
视图渲染完成
↓
afterCompletion() → 无论是否异常都会执行
参数详解
| 参数 | 类型 | 说明 |
|---|---|---|
| request | HttpServletRequest | 当前HTTP请求对象 |
| response | HttpServletResponse | 当前HTTP响应对象 |
| handler | Object | 处理器对象(HandlerMethod) |
| ex | Exception | 处理过程中抛出的异常,无异常则为null |
基本实现
Java
@Component
public class LogInterceptor implements HandlerInterceptor {
private static final String START_TIME = "startTime";
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
request.setAttribute(START_TIME, System.currentTimeMillis());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
Long startTime = (Long) request.getAttribute(START_TIME);
long duration = System.currentTimeMillis() - startTime;
String uri = request.getRequestURI();
String method = request.getMethod();
int status = response.getStatus();
if (ex != null) {
log.error("请求异常: {} {}, 耗时: {}ms, 状态: {}, 异常: {}",
method, uri, duration, status, ex.getMessage());
} else {
log.info("请求完成: {} {}, 耗时: {}ms, 状态: {}",
method, uri, duration, status);
}
}
}
获取处理器信息
Java
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
// 获取Controller类名和方法名
String className = handlerMethod.getBeanType().getSimpleName();
String methodName = handlerMethod.getMethod().getName();
// 获取方法参数
MethodParameter[] params = handlerMethod.getMethodParameters();
log.info("处理器: {}.{}", className, methodName);
}
}
异常处理场景
Java
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
// 正常执行完成
if (ex == null) {
log.info("请求正常完成: {}", request.getRequestURI());
return;
}
// 异常处理
if (ex instanceof BusinessException) {
BusinessException be = (BusinessException) ex;
log.warn("业务异常: code={}, message={}", be.getCode(), be.getMessage());
} else if (ex instanceof IllegalArgumentException) {
log.warn("参数异常: {}", ex.getMessage());
} else {
log.error("系统异常: ", ex);
}
}
资源清理
Java
@Component
public class ResourceCleanupInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
// 在请求开始时创建资源
request.setAttribute("dbContext", new DbContext());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
// 请求结束后清理资源
DbContext dbContext = (DbContext) request.getAttribute("dbContext");
if (dbContext != null) {
dbContext.close();
request.removeAttribute("dbContext");
}
// 清理ThreadLocal
UserContext.clear();
TraceContext.clear();
}
}
性能监控统计
Java
@Component
public class PerformanceInterceptor implements HandlerInterceptor {
private final MeterRegistry meterRegistry;
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
request.setAttribute("startTime", System.nanoTime());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
long startTime = (long) request.getAttribute("startTime");
long duration = System.nanoTime() - startTime;
String uri = request.getRequestURI();
String method = request.getMethod();
int status = response.getStatus();
// 记录到监控系统
Timer.builder("http.request.duration")
.tag("uri", uri)
.tag("method", method)
.tag("status", String.valueOf(status))
.tag("success", ex == null ? "true" : "false")
.register(meterRegistry)
.record(duration, TimeUnit.NANOSECONDS);
}
}
多拦截器执行顺序
当配置多个拦截器时,afterCompletion执行顺序与preHandle相反:
text
// preHandle执行顺序: Interceptor1 → Interceptor2 → Interceptor3
// afterCompletion执行顺序: Interceptor3 → Interceptor2 → Interceptor1
| 方法 | 执行顺序 |
|---|---|
| preHandle | 顺序执行 |
| postHandle | 逆序执行 |
| afterCompletion | 逆序执行 |
afterCompletion只在preHandle返回true的拦截器上执行。
要点总结
- afterCompletion在视图渲染完成后执行
- 无论Controller是否抛出异常都会执行
- ex参数携带处理过程中的异常信息
- 适合资源清理、日志记录、性能统计等场景
- 执行顺序与preHandle相反
📝 发现内容有误?点击此处直接编辑