前几天,因为准备面试,重新复习了下Spring MVC的源码(其实也只是看了DispatcherServlet类),设计到,Spring MVC 的请求流程、Spring 拦截器的拦截原理等记录下,下次复习简单些。
在Spring mvc 中拦截器有很多种实现方式,大同小异。
可以通过实现 HandlerInterceptor 接口实现
/**
* @program: demo
* @author: Mr.Lemon
* @create: 2020/6/1
**/
@Component
public class ServiceInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
还可以通过继承 HandlerInterceptorAdapter 实现,
/**
* @program: demo
* @author: Mr.Lemon
* @create: 2020/3/31
**/
@Component
public class TestInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println(request.getRequestURI());
return true;
}
}
其实这种方式最终调用的也是 HandlerIntrceptor 接口。调用链:HandlerInterceptorAdapter — 实现 —> AsyncHandlerInterceptor — 继承 —> HandlerInterceptor
public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor {
......
此处省略源码
......
}
public interface AsyncHandlerInterceptor extends HandlerInterceptor {
default void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
}
}
主要看org.springframework.web.servlet.DispatcherServlet#doDispatch 这个方法。
DispatcherServlet:
public class DispatcherServlet extends FrameworkServlet {
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
......省略部分代码
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
......省略部分代码
mappedHandler.applyPostHandle(processedRequest, response, mv);
......省略部分代码
// 方法内部调用 interceptor.afterCompletion
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
......省略部分代码
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
if (mappedHandler != null) {
// Exception (if any) is already handled..
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
/**
* Apply afterConcurrentHandlerStarted callback on mapped AsyncHandlerInterceptors.
*/
void applyAfterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response) {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = interceptors.length - 1; i >= 0; i--) {
if (interceptors[i] instanceof AsyncHandlerInterceptor) {
try {
AsyncHandlerInterceptor asyncInterceptor = (AsyncHandlerInterceptor) interceptors[i];
asyncInterceptor.afterConcurrentHandlingStarted(request, response, this.handler);
}
catch (Throwable ex) {
logger.error("Interceptor [" + interceptors[i] + "] failed in afterConcurrentHandlingStarted", ex);
}
}
}
}
}
}
上面的代码其实很清晰了,在贴一段 applyPreHandle 和 applyPostHandle 以及 afterCompletion调用的代码:
public class HandlerExecutionChain {
......省略代码....
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;
}
/**
* Apply postHandle methods of registered interceptors.
*/
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);
}
}
}
/**
* Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
* Will just invoke afterCompletion for all interceptors whose preHandle invocation
* has successfully completed and returned true.
*/
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);
}
}
}
}
/**
* Apply afterConcurrentHandlerStarted callback on mapped AsyncHandlerInterceptors.
*/
void applyAfterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response) {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = interceptors.length - 1; i >= 0; i--) {
if (interceptors[i] instanceof AsyncHandlerInterceptor) {
try {
AsyncHandlerInterceptor asyncInterceptor = (AsyncHandlerInterceptor) interceptors[i];
asyncInterceptor.afterConcurrentHandlingStarted(request, response, this.handler);
}
catch (Throwable ex) {
logger.error("Interceptor [" + interceptors[i] + "] failed in afterConcurrentHandlingStarted", ex);
}
}
}
}
}
......省略代码......
}
其实源码贴到这里,原理已经很清晰了。其实就是在 ha.handle (controller调用) 之前,循环调用 每个拦截器的 preHandle 方法,在controller方法。运行之后,视图返回之前,循环调用每个拦截器的 postHandle方法。在返回视图之后,在调用 interceptor.afterCompletion。总结起来其实就是 HandlerExecutionChain封装保存了拦截器列表,DispatcherServlet 在进行controller的调用的过程中,调用 HandlerExecutionChain 类里的对应的拦截器的对应阶段代码。
下面的代码是把拦截器加载到spring mvc的 InterceptorRegistry里的
/**
* @program: demo
* @author: Mr.Lemon
* @create: 2020/3/31
**/
@Configuration
public class WebConfig extends WebMvcConfigurationSupport {
@Autowired
private TestInterceptor testInterceptor;
@Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(testInterceptor);
}
}
就这样了?当然不是,经过我的层层搜寻,他们最后调用的是org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#getInterceptors,
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
protected final Object[] getInterceptors(
FormattingConversionService mvcConversionService,
ResourceUrlProvider mvcResourceUrlProvider) {
if (this.interceptors == null) {
InterceptorRegistry registry = new InterceptorRegistry();
addInterceptors(registry);
registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService));
registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider));
this.interceptors = registry.getInterceptors();
}
return this.interceptors.toArray();
}
// 这个就是上面我们自己实现的WebConfig 里重写的方法addInterceptors,
protected void addInterceptors(InterceptorRegistry registry) {
}
}
其实研究源码总结起来的调用链路就是:HandlerExecutionChain 的拦截器是从org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandlerExecutionChain 来的,而该方法里的 adaptedInterceptors 是从 org.springframework.web.servlet.handler.AbstractHandlerMapping#initInterceptors 方法的interceptors里获取的,而 interceptors 是从 org.springframework.web.servlet.handler.AbstractHandlerMapping#setInterceptors 这个方法set进去的,而调用这个set方法的,其实都是调用的 org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#getInterceptors。上面链路的全部代码如下:
public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
implements HandlerMapping, Ordered, BeanNameAware {
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
protected void initInterceptors() {
if (!this.interceptors.isEmpty()) {
for (int i = 0; i < this.interceptors.size(); i++) {
Object interceptor = this.interceptors.get(i);
if (interceptor == null) {
throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");
}
this.adaptedInterceptors.add(adaptInterceptor(interceptor));
}
}
}
public void setInterceptors(Object... interceptors) {
this.interceptors.addAll(Arrays.asList(interceptors));
}
protected final Object[] getInterceptors(
FormattingConversionService mvcConversionService,
ResourceUrlProvider mvcResourceUrlProvider) {
if (this.interceptors == null) {
InterceptorRegistry registry = new InterceptorRegistry();
addInterceptors(registry);
registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService));
registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider));
this.interceptors = registry.getInterceptors();
}
return this.interceptors.toArray();
}
}
研究源码就是这么朴实无华,且枯燥