SpringMVC-拦截器

一、拦截器
SpringMVC提供了拦截器在处理请求之前,之后,渲染视图后执行逻辑处理。接口是HandlerInterceptor。preHandle方法在处理请求之前执行,postHandle方法是在处理请求后渲染视图视图之前执行。afterCompletion方法在渲染视图后执行。

二、解析interceptor

<mvc:interceptors>
	<mvc:interceptor>
		<mvc:mapping path="/*"/>
		<bean id="myInteceptor" class="mvc.inteceptor.MyInteceptor"/>
	</mvc:interceptor>
</mvc:interceptors>

interceptor标签由InterceptorsBeanDefinitionParser解析。

InterceptorsBeanDefinitionParser.parse(Element element, ParserContext context)

public BeanDefinition parse(Element element, ParserContext context) {
	context.pushContainingComponent(
			new CompositeComponentDefinition(element.getTagName(), context.extractSource(element)));

	RuntimeBeanReference pathMatcherRef = null;
	if (element.hasAttribute("path-matcher")) {
		pathMatcherRef = new RuntimeBeanReference(element.getAttribute("path-matcher"));
	}

	List<Element> interceptors = DomUtils.getChildElementsByTagName(element, "bean", "ref", "interceptor");
	for (Element interceptor : interceptors) {
		RootBeanDefinition mappedInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);
		mappedInterceptorDef.setSource(context.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 = context.getDelegate().parsePropertySubElement(beanElem, null);
		}
		else {
			interceptorBean = context.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 = context.getReaderContext().registerWithGeneratedName(mappedInterceptorDef);
		context.registerComponent(new BeanComponentDefinition(mappedInterceptorDef, beanName));
	}

	context.popAndRegisterContainingComponent();
	return null;
}

将每个interceptor元素解析成MappedInterceptor。

三、执行拦截器

RequestMappingHandlerMapping继承了ApplicationObjectSupport抽象类,ApplicationObjectSupport实现了ApplicationContextAware接口。在实例化RequestMappingHandlerMapping会调用ApplicationContextAware.setApplicationContext方法。会调用到AbstractHandlerMapping.initApplicationContext():

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


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

detectMappedInterceptors从beanFactory中获取类型为MappedInterceptor的所有bean并加入mappedInterceptors集合中.

DispatcherServlet在处理请求获取handle时,会调用AbstractHandlerMapping.getHandlerExecutionChain

	protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
	HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
			(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

	for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
		if (interceptor instanceof MappedInterceptor) {
			MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
			if (mappedInterceptor.matches(request)) {
				chain.addInterceptor(mappedInterceptor.getInterceptor());
			}
		}
		else {
			chain.addInterceptor(interceptor);
		}
	}
	return chain;
}

遍历adaptedInterceptors集合,如果HandlerInterceptor是MappedInterceptor类型,则判断MappedInterceptor是否匹配请求,如果匹配则加入HandlerExecutionChain。通过在配置拦截器mvc:mapping的path和请求路径是否匹配来判断MappedInterceptor是否匹配请求。如果HandlerInterceptor不是MappedInterceptor类型则加入HandlerExecutionChain。

DispatcherServlet.doDispatch(HttpServletRequest request, HttpServletResponse response)处理请求时:

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) {
				noHandlerFound(processedRequest, response);
				return;
			}

			// Determine handler adapter for the current request.
			HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

			// Process last-modified header, if supported by the handler.
			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;
				}
			}

			if (!mappedHandler.applyPreHandle(processedRequest, response)) {
				return;
			}

			// Actually invoke the handler.
			mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

			if (asyncManager.isConcurrentHandlingStarted()) {
				return;
			}

			applyDefaultViewName(processedRequest, mv);
			mappedHandler.applyPostHandle(processedRequest, response, mv);
		}
		catch (Exception ex) {
			dispatchException = ex;
		}
		catch (Throwable err) {
			// As of 4.3, we're processing Errors thrown from handler methods as well,
			// making them available for @ExceptionHandler methods and other scenarios.
			dispatchException = new NestedServletException("Handler dispatch failed", err);
		}
		processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
	}
	catch (Exception ex) {
		triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
	}
	catch (Throwable err) {
		triggerAfterCompletion(processedRequest, response, mappedHandler,
				new NestedServletException("Handler processing failed", err));
	}
	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);
			}
		}
	}
}

调用getHandler获取HandlerExecutionChain后,调用mappedHandler.applyPreHandle(processedRequest, response)执行拦截器的preHandle方法,如果有一个拦截器返回false,则退出。调用HandlerAdapter.handle执行实际处理请求。在调用mappedHandler.applyPostHandle逆序执行拦截器postHandle的方法。processDispatchResult渲染视图和处理异常完成后调用mappedHandler.triggerAfterCompletion执行拦截器的afterCompletion方法。

posted @   shigp1  阅读(73)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示