版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jeikerxiao/article/details/88292534
Spring MVC 拦截器的配置使用
1.实现拦截器
实现 HandlerInterceptor 接口,实现里面的三个方法。
第一个拦截器:
/**
* Description: 第一个拦截器
* User: jeikerxiao
* Date: 2019/3/6 9:33 PM
*/
public class FirstHandlerIntercepter implements HandlerInterceptor {
private static final Logger log = LoggerFactory.getLogger(FirstHandlerIntercepter.class);
/**
* 执行期:进入Handler方法之前执行
* 应用:用于身份认证、身份授权
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// false代表拦截,不向下执行
// true代表通过,为方便调试下一步,下面设置为true
log.info("first Interceptor preHandle");
return true;
}
/**
* 执行期:进入Handler方法之后,返回ModelAndView之前
* 应用:用于向ModelAndView中填充公共数据、指定统一的视图
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("first Interceptor postHandle");
}
/**
* 执行期:进入Handler完成
* 应用:用于统一异常处理、统一日志处理
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("first Interceptor afterCompletion");
}
}
第二个拦截器:
/**
* Description: 第二个拦截器
* User: jeikerxiao
* Date: 2019/3/7 9:09 AM
*/
public class SecondHandlerIntercepter implements HandlerInterceptor {
private final Logger log = LoggerFactory.getLogger(SecondHandlerIntercepter.class);
/**
* 执行期:进入Handler方法之前执行
* 应用:用于身份认证、身份授权
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// false代表拦截,不向下执行
// true代表通过,为方便调试下一步,下面设置为true
log.info("second Interceptor preHandle");
return true;
}
/**
* 执行期:进入Handler方法之后,返回ModelAndView之前
* 应用:用于向ModelAndView中填充公共数据、指定统一的视图
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("second Interceptor postHandle");
}
/**
* 执行期:进入Handler完成
* 应用:用于统一异常处理、统一日志处理
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("second Interceptor afterCompletion");
}
}
2.配置拦截器
在spring-mvc 的配置文件中增加如下拦截器配置,增加URL路由拦截规则,并匹配指定好对应的拦截器类。
例如,演示使用的是 spring-mvc.xml
配置文件:
<!-- 配置拦截器 -->
<mvc:interceptors>
<!-- 注意多个拦截器顺序执行 -->
<mvc:interceptor>
<!-- 拦截所有URL -->
<mvc:mapping path="/**"/>
<bean class="com.jeiker.intercepter.FirstHandlerIntercepter"/>
</mvc:interceptor>
<mvc:interceptor>
<!-- 拦截指定URL -->
<mvc:mapping path="/user/**"/>
<bean class="com.jeiker.intercepter.SecondHandlerIntercepter"/>
</mvc:interceptor>
</mvc:interceptors>
3.测试使用的Controller
@RestController
@RequestMapping("/user")
public class UserController {
private static final Logger log = LoggerFactory.getLogger(UserController.class);
@GetMapping("/hello")
public Map<String, String> hello() {
log.info("hello");
return Collections.singletonMap("message", "good");
}
}
4.运行查看日志输出
接口访问:
GET:http://localhost:8080/user/hello
可以看出日志输出如下:
03-07 10:15:14.614 [DEBUG] [org.springframework.web.servlet.DispatcherServlet: 79] - GET "/user/hello", parameters={}
03-07 10:15:17.369 [DEBUG] [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping:420] - Mapped to public java.util.Map<java.lang.String, java.lang.String> com.jeiker.controller.UserController.hello()
03-07 10:15:20.355 [ INFO] [com.jeiker.intercepter.FirstHandlerIntercepter: 28] - first Interceptor preHandle
03-07 10:15:20.911 [ INFO] [com.jeiker.intercepter.SecondHandlerIntercepter: 28] - second Interceptor preHandle
03-07 10:15:21.427 [ INFO] [com.jeiker.controller.UserController: 26] - hello
03-07 10:15:21.429 [DEBUG] [org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor:267] - Using 'application/json', given [*/*] and supported [application/json, application/*+json]
03-07 10:15:21.429 [DEBUG] [org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor: 79] - Writing [{message=good}]
03-07 10:15:23.570 [ INFO] [com.jeiker.intercepter.SecondHandlerIntercepter: 38] - second Interceptor postHandle
03-07 10:15:24.261 [ INFO] [com.jeiker.intercepter.FirstHandlerIntercepter: 38] - first Interceptor postHandle
03-07 10:15:27.271 [ INFO] [com.jeiker.intercepter.SecondHandlerIntercepter: 47] - second Interceptor afterCompletion
03-07 10:15:27.924 [ INFO] [com.jeiker.intercepter.FirstHandlerIntercepter: 47] - first Interceptor afterCompletion
03-07 10:15:27.925 [DEBUG] [org.springframework.web.servlet.DispatcherServlet:1123] - Completed 200 OK
由日志可以看出拦截器里的方法执行顺序为:
- Interceptor1 - preHandle()
- Interceptor2 - preHandle()
- UserController - hello()
- Interceptor2 - postHandle()
- Interceptor1 - postHandle()
- Interceptor2 - afterCompletion()
- Interceptor1 - afterCompletion()
spring mvc 源码分析拦截器执行顺序分析
1. DispatcherServlet中doDispatch()方法
查看分析DispatcherServlet.class
中doDispatch()
方法
扫描二维码关注公众号,回复:
6407029 查看本文章
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
// 判断是否为文件上传请求
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
// 为当前请求查找Controller对应的方法,如找到示例中的UserController.hello()方法
mappedHandler = getHandler(processedRequest);
... ...
// Determine handler adapter for the current request.
// 1.确定对应Handler的执行链,在此处决定HandlerExecutionChain,
// 也就是决定URL对应要执行的拦截器和Handler
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
// 处理请求头中的last-modified参数
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 2.执行请求对应拦截器的preHandle()方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
// 3.实际调用对应Handler并执行,如执行示例中的UserController.hello()方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
// 4.执行请求对应拦截器的 postHandle() 方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
... ...
// 处理最后的返回结果
// 5.里面执行请求对应拦截器的 afterCompletion() 方法
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
... ...
}
// 5.里面执行请求对应拦截器的 afterCompletion() 方法
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
... ...
if (mappedHandler != null) {
// 5.执行请求对应拦截器的 afterCompletion() 方法
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
2. 查看HandlerExecutionChain中方法执行顺序
查看HandlerExecutionChain中方法执行顺序,以确定Handler 执行链的顺序。
建议使用debug模式,为每个方法打上断点进行调试跟踪方法的执行。
并结合两个自己注册实现的HandlerInterceptor 和执行的Controller中的hello()方法中的日志位置。
打开HandlerExecutionChain.class类文件:
public class HandlerExecutionChain {
... ...
/**
* 调用执行应用程序中注册的拦截器的 preHandle() 方法
*/
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
/**
* 调用执行应用程序中注册的拦截器的 postHandle() 方法
*/
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
/**
* 调用执行应用程序中注册的拦截器的 afterCompletion() 方法
*/
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}
... ...
}
到此分析Spring VMC的拦截器工作的顺序和部分源码解读就完成了。