Spring 拦截器原理

Spring 拦截器原理

文章目录

  • Spring 拦截器原理
    • 前言
    • Spring MVC 拦截器的几种实现
      • 实现接口形式实现
      • 继承类的形式实现
    • Spring MVC 拦截器的原理
    • 拦截器什么时候加载的
    • 最后

前言

前几天,因为准备面试,重新复习了下Spring MVC的源码(其实也只是看了DispatcherServlet类),设计到,Spring MVC 的请求流程、Spring 拦截器的拦截原理等记录下,下次复习简单些。

Spring MVC 拦截器的几种实现

在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 {
	}

}

Spring MVC 拦截器的原理

主要看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);
					}
				}
			}
		}
	}
}

上面的代码其实很清晰了,在贴一段 applyPreHandleapplyPostHandle 以及 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();
	}
}

最后

研究源码就是这么朴实无华,且枯燥

你可能感兴趣的:(spring,源码)