SpringMVC源码总结(十一)mvc:interceptors拦截器介绍
本文章针对mvc:interceptors标签进行介绍,它的注册过程以及在访问时的拦截过程。
首先说下接口HandlerInterceptor,它有如下三个方法:
Java代码
正常情况下,对于preHandle就是在在处理函数之前先执行,然后再执行处理函数,接着执行postHandle,最后再执行afterCompletion。afterCompletion无论是否出错是肯定要执行的,而postHandle则不是,不一定会执行。之后看源代码就知道他们的执行情况。
AsyncHandlerInterceptor接口则增添了afterConcurrentHandlingStarted方法,对于此还未研究,先不讨论。
HandlerInterceptorAdapter则默认实现了上述的接口,所以当我们仅仅要实现某个方法时,只需继承HandlerInterceptorAdapter,然后覆盖相应的方法。
然后我们就写一个类继承HandlerInterceptorAdapter来进行实验:LoginInterceptor如下:
Java代码
没有做具体的内容,仅仅是打印出一些信息,方便查看执行顺序。
该接口的基本内容说完了,然后就看下它的配置说明:
Java代码
其实在mvc:interceptors标签中,有两种类型的配置,一种直接配置一个bean(bean和ref归为一类),另一种还要配置上拦截的路径和排除的路径。直接配置的bean那就代表对所有的请求进行拦截,而对于mvc:interceptor则代表有着更精细的控制。
而mvc:interceptors的属性path-matcher则表示配置一个自定义的PathMatcher,它主要用来处理路径的匹配规则,默认采用的PathMatcher为AntPathMatcher,具有ant风格的路径规则,如?表示任何单字符,*表示0个或多个字符,**表示0个或多个目录。
对于本工程来说具体的配置如下:
Java代码
然后就进行源代码分析:
如何来处理xml文件中所配置的这些HandlerInterceptor的呢?
对于mvc:interceptors的解析同样需要我们去看BeanDefinitionParser的实现类,最终会找到InterceptorsBeanDefinitionParser:
Java代码
这里就引出来MappedInterceptor的结构类型:
Java代码
到这里就很明白了,虽然在mvc:interceptors标签中,配置interceptor形式不一样,但是最终都将以MappedInterceptor形式存储,同时来看下MappedInterceptor的match的方法:
Java代码
这里便是PathMatcher对于excludePatterns、includePatterns 的使用规则,同时表明本身的PathMatcher若为空,则使用外部传来的PathMatcher。
至此解析mvc:interceptors标签的过程就完成了。它们最终会注册到ApplicationContext的上下文环境中,等待被使用。
谁会是他们的使用者呢?我们慢慢来看:
对于每一个请求,HandlerMapping都会找到对应的handler,并最终封装成一个HandlerExecutionChain,这个HandlerExecutionChain包含有handler和它对应的interceptors,HandlerExecutionChain如下:
Java代码
既然是由HandlerMapping来产生的HandlerExecutionChain,则它需要为每一个它所管辖的handler来装配HandlerInterceptor。所以HandlerMapping必然是mvc:interceptors标签内容的使用者。
使用者:AbstractHandlerMapping,它的属性有:
Java代码
这里便可以看到,它所使用的默认的PathMatcher为AntPathMatcher。接下来我们看下AbstractHandlerMapping的初始化方法:
Java代码
detectMappedInterceptors探测ApplicationContext中已经解析过的MappedInterceptor,如下:
Java代码
全部存放到AbstractHandlerMapping的mappedInterceptors属性上。
然后我们继续看看在请求到来时的具体拦截过程:
Java代码
对于每个请求先找到对应的HandlerMapping,然后由这个handlerMapping来找到对应请求的handler,然后由handlerMapping自身的interceptor和这个handler来构建一个HandlerExecutionChain。代码如下:
Java代码
这里便是找到一个合适的HandlerMapping,继续看下hm.getHandler(request)这个方法。
Java代码
这里便是找到对应请求的handler。getHandlerExecutionChain(handler, request)这里便是构建HandlerExecutionChain的地方:
Java代码
对于我们关注的重点为它会遍历AbstarctHandlerMapping的mappedInterceptors属性,然后使用默认的pathMatcher,即AntPathMatcher来判断当前的请求是否符合拦截条件,若符合则将mappedInterceptor放进HandlerExecutionChain 中。
至此一个HandlerExecutionChain便构建好了,包含一个handler和这个handler对应的interceptor。然后看下interceptor的执行过程:
Java代码
首先说下接口HandlerInterceptor,它有如下三个方法:
Java代码

- boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
- throws Exception;
- void postHandle(
- HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
- throws Exception;
- void afterCompletion(
- HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
- throws Exception;

正常情况下,对于preHandle就是在在处理函数之前先执行,然后再执行处理函数,接着执行postHandle,最后再执行afterCompletion。afterCompletion无论是否出错是肯定要执行的,而postHandle则不是,不一定会执行。之后看源代码就知道他们的执行情况。
AsyncHandlerInterceptor接口则增添了afterConcurrentHandlingStarted方法,对于此还未研究,先不讨论。
HandlerInterceptorAdapter则默认实现了上述的接口,所以当我们仅仅要实现某个方法时,只需继承HandlerInterceptorAdapter,然后覆盖相应的方法。
然后我们就写一个类继承HandlerInterceptorAdapter来进行实验:LoginInterceptor如下:
Java代码

- @Override
- public boolean preHandle(HttpServletRequest request,
- HttpServletResponse response, Object handler) throws Exception {
- System.out.println("preHandle");
- return super.preHandle(request, response, handler);
- }
- @Override
- public void postHandle(HttpServletRequest request,
- HttpServletResponse response, Object handler,
- ModelAndView modelAndView) throws Exception {
- System.out.println("postHandle");
- super.postHandle(request, response, handler, modelAndView);
- }
- @Override
- public void afterCompletion(HttpServletRequest request,
- HttpServletResponse response, Object handler, Exception ex)
- throws Exception {
- System.out.println("afterCompletion");
- super.afterCompletion(request, response, handler, ex);
- }
- @Override
- public void afterConcurrentHandlingStarted(HttpServletRequest request,
- HttpServletResponse response, Object handler) throws Exception {
- System.out.println("afterConcurrentHandlingStarted");
- super.afterConcurrentHandlingStarted(request, response, handler);
- }

没有做具体的内容,仅仅是打印出一些信息,方便查看执行顺序。
该接口的基本内容说完了,然后就看下它的配置说明:
Java代码

- <mvc:interceptors path-matcher="xxx">
- <mvc:interceptor>
- <mvc:mapping path="xxx"/>
- <mvc:exclude-mapping path="xxxx"/>
- <bean class="xxxx"></bean>
- </mvc:interceptor>
- <bean class="com.lg.mvc.interceptor.LoginInterceptor" />
- </mvc:interceptors>

其实在mvc:interceptors标签中,有两种类型的配置,一种直接配置一个bean(bean和ref归为一类),另一种还要配置上拦截的路径和排除的路径。直接配置的bean那就代表对所有的请求进行拦截,而对于mvc:interceptor则代表有着更精细的控制。
而mvc:interceptors的属性path-matcher则表示配置一个自定义的PathMatcher,它主要用来处理路径的匹配规则,默认采用的PathMatcher为AntPathMatcher,具有ant风格的路径规则,如?表示任何单字符,*表示0个或多个字符,**表示0个或多个目录。
对于本工程来说具体的配置如下:
Java代码

- <mvc:interceptors>
- <bean class="com.lg.mvc.interceptor.LoginInterceptor" />
- </mvc:interceptors>

然后就进行源代码分析:
如何来处理xml文件中所配置的这些HandlerInterceptor的呢?
对于mvc:interceptors的解析同样需要我们去看BeanDefinitionParser的实现类,最终会找到InterceptorsBeanDefinitionParser:
Java代码

- public BeanDefinition parse(Element element, ParserContext parserContext) {
- CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
- parserContext.pushContainingComponent(compDefinition);
- //判断是否自定义了PathMatcher
- RuntimeBeanReference pathMatcherRef = null;
- if (element.hasAttribute("path-matcher")) {
- pathMatcherRef = new RuntimeBeanReference(element.getAttribute("path-matcher"));
- }
- //获取所有的interceptor,在这里我们可以看到所有的interceptor最终都会构建成一个
- //MappedInterceptor
- List<Element> interceptors = DomUtils.getChildElementsByTagName(element, "bean", "ref", "interceptor");
- for (Element interceptor : interceptors) {
- RootBeanDefinition mappedInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);
- mappedInterceptorDef.setSource(parserContext.extractSource(interceptor));
- mappedInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
- ManagedList<String> includePatterns = null;
- ManagedList<String> excludePatterns = null;
- Object interceptorBean;
- if ("interceptor".equals(interceptor.getLocalName())) {
- includePatterns = getIncludePatterns(interceptor, "mapping");
- excludePatterns = getIncludePatterns(interceptor, "exclude-mapping");
- Element beanElem = DomUtils.getChildElementsByTagName(interceptor, "bean", "ref").get(0);
- interceptorBean = parserContext.getDelegate().parsePropertySubElement(beanElem, null);
- }
- else {
- interceptorBean = parserContext.getDelegate().parsePropertySubElement(interceptor, null);
- }
- mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, includePatterns);
- mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, excludePatterns);
- mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(2, interceptorBean);
- if (pathMatcherRef != null) {
- mappedInterceptorDef.getPropertyValues().add("pathMatcher", pathMatcherRef);
- }
- String beanName = parserContext.getReaderContext().registerWithGeneratedName(mappedInterceptorDef);
- parserContext.registerComponent(new BeanComponentDefinition(mappedInterceptorDef, beanName));
- }
- parserContext.popAndRegisterContainingComponent();
- return null;
- }

这里就引出来MappedInterceptor的结构类型:
Java代码

- private final String[] includePatterns;
- private final String[] excludePatterns;
- private final HandlerInterceptor interceptor;
- private PathMatcher pathMatcher;

到这里就很明白了,虽然在mvc:interceptors标签中,配置interceptor形式不一样,但是最终都将以MappedInterceptor形式存储,同时来看下MappedInterceptor的match的方法:
Java代码

- public boolean matches(String lookupPath, PathMatcher pathMatcher) {
- PathMatcher pathMatcherToUse = (this.pathMatcher != null) ? this.pathMatcher : pathMatcher;
- if (this.excludePatterns != null) {
- for (String pattern : this.excludePatterns) {
- if (pathMatcherToUse.match(pattern, lookupPath)) {
- return false;
- }
- }
- }
- if (this.includePatterns == null) {
- return true;
- }
- else {
- for (String pattern : this.includePatterns) {
- if (pathMatcherToUse.match(pattern, lookupPath)) {
- return true;
- }
- }
- return false;
- }
- }

这里便是PathMatcher对于excludePatterns、includePatterns 的使用规则,同时表明本身的PathMatcher若为空,则使用外部传来的PathMatcher。
至此解析mvc:interceptors标签的过程就完成了。它们最终会注册到ApplicationContext的上下文环境中,等待被使用。
谁会是他们的使用者呢?我们慢慢来看:
对于每一个请求,HandlerMapping都会找到对应的handler,并最终封装成一个HandlerExecutionChain,这个HandlerExecutionChain包含有handler和它对应的interceptors,HandlerExecutionChain如下:
Java代码

- private final Object handler;
- private HandlerInterceptor[] interceptors;
- private List<HandlerInterceptor> interceptorList;
- private int interceptorIndex = -1;

既然是由HandlerMapping来产生的HandlerExecutionChain,则它需要为每一个它所管辖的handler来装配HandlerInterceptor。所以HandlerMapping必然是mvc:interceptors标签内容的使用者。
使用者:AbstractHandlerMapping,它的属性有:
Java代码

- private PathMatcher pathMatcher = new AntPathMatcher();
- private final List<Object> interceptors = new ArrayList<Object>();
- private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<HandlerInterceptor>();
- private final List<MappedInterceptor> mappedInterceptors = new ArrayList<MappedInterceptor>();

这里便可以看到,它所使用的默认的PathMatcher为AntPathMatcher。接下来我们看下AbstractHandlerMapping的初始化方法:
Java代码

- protected void initApplicationContext() throws BeansException {
- extendInterceptors(this.interceptors);
- detectMappedInterceptors(this.mappedInterceptors);
- initInterceptors();
- }

detectMappedInterceptors探测ApplicationContext中已经解析过的MappedInterceptor,如下:
Java代码

- protected void detectMappedInterceptors(List<MappedInterceptor> mappedInterceptors) {
- mappedInterceptors.addAll(
- BeanFactoryUtils.beansOfTypeIncludingAncestors(
- getApplicationContext(), MappedInterceptor.class, true, false).values());
- }

全部存放到AbstractHandlerMapping的mappedInterceptors属性上。
然后我们继续看看在请求到来时的具体拦截过程:
Java代码

- 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.
- mappedHandler = getHandler(processedRequest);
- //略
- }

对于每个请求先找到对应的HandlerMapping,然后由这个handlerMapping来找到对应请求的handler,然后由handlerMapping自身的interceptor和这个handler来构建一个HandlerExecutionChain。代码如下:
Java代码

- protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
- for (HandlerMapping hm : this.handlerMappings) {
- if (logger.isTraceEnabled()) {
- logger.trace(
- "Testing handler map [" + hm + "] in DispatcherServlet with name "" + getServletName() + """);
- }
- HandlerExecutionChain handler = hm.getHandler(request);
- if (handler != null) {
- return handler;
- }
- }
- return null;
- }

这里便是找到一个合适的HandlerMapping,继续看下hm.getHandler(request)这个方法。
Java代码

- public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
- Object handler = getHandlerInternal(request);
- if (handler == null) {
- handler = getDefaultHandler();
- }
- if (handler == null) {
- return null;
- }
- // Bean name or resolved handler?
- if (handler instanceof String) {
- String handlerName = (String) handler;
- handler = getApplicationContext().getBean(handlerName);
- }
- return getHandlerExecutionChain(handler, request);
- }

这里便是找到对应请求的handler。getHandlerExecutionChain(handler, request)这里便是构建HandlerExecutionChain的地方:
Java代码

- protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
- HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
- (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
- chain.addInterceptors(getAdaptedInterceptors());
- String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
- for (MappedInterceptor mappedInterceptor : this.mappedInterceptors) {
- if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
- chain.addInterceptor(mappedInterceptor.getInterceptor());
- }
- }
- return chain;
- }

对于我们关注的重点为它会遍历AbstarctHandlerMapping的mappedInterceptors属性,然后使用默认的pathMatcher,即AntPathMatcher来判断当前的请求是否符合拦截条件,若符合则将mappedInterceptor放进HandlerExecutionChain 中。
至此一个HandlerExecutionChain便构建好了,包含一个handler和这个handler对应的interceptor。然后看下interceptor的执行过程:
Java代码

- 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.
- mappedHandler = getHandler(processedRequest);
- if (mappedHandler == null || mappedHandler.getHandler() == null) {
- noHandlerFound(processedRequest, response);
- return;
- }
- // Determine handler adapter for the current request.
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。