《spring mvc》1 源码分析

1 根据url获取HandlerExecutionChain

从debug的堆栈图中可以看到HandlerExecutionChain的结构:

(1)url对应的controller bean

(2)url对应的method

(3)所有该请求url拦截规则的intercepter

2 获取处理器

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

3 遍历拦截器并调用拦截器的preHandle

// Apply preHandle methods of registered interceptors.
HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
if (interceptors != null) {
	for (int i = 0; i < interceptors.length; i++) {
		HandlerInterceptor interceptor = interceptors[i];
		if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler()))           {
		    triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
			return;
		}
		interceptorIndex = i;
	}
}

4 利用java 反射调用controller的实际方法,其中数据绑定部分的代码,在controller中可使用@InitBinder

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

// RequestMappingHandlerAdapter
protected final ModelAndView handleInternal(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    ...
    return invokeHandleMethod(request, response, handlerMethod);
    ...
}

private ModelAndView invokeHandleMethod(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

    ...
    // 在controller中用@InitBinder就是在这里面起作用,比如对String类型进行html编码
    WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
    ...
    requestMappingMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);
    ...
}

// InvocableHandlerMethod
private Object invoke(Object... args) throws Exception{
ReflectionUtils.makeAccessible(getBridgedMethod());
...
    return getBridgedMethod().invoke(getBean(), args);
...
}

5 调用拦截器的postHandle方法

 mappedHandler.applyPostHandle(processedRequest, response, mv);

6 处理异常和结果,在controller中可以定义@ExceptionHandler({BindException.class,WebException.class, ConstraintViolationException.class, ValidationException.class})注解进行异常处理。

(1)异常处理

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);


private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception){
    ...
     mv = processHandlerException(request, response, handler, exception);    
    ...
}

(2)返回结果处理,最后调用的是javax包的forward、include、sendRedirect等等方法

@Override
	public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
		if (logger.isTraceEnabled()) {
			logger.trace("Rendering view with name '" + this.beanName + "' with model " + model +
				" and static attributes " + this.staticAttributes);
		}

		Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
		prepareResponse(request, response);
		renderMergedOutputModel(mergedModel, request, response);
	}

// 最后调用的是javax包的forward、include等等方法
@Override
	protected void renderMergedOutputModel(
			Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {

		// Determine which request handle to expose to the RequestDispatcher.
		HttpServletRequest requestToExpose = getRequestToExpose(request);

		// Expose the model object as request attributes.
		exposeModelAsRequestAttributes(model, requestToExpose);

		// Expose helpers as request attributes, if any.
		exposeHelpers(requestToExpose);

		// Determine the path for the request dispatcher.
		String dispatcherPath = prepareForRendering(requestToExpose, response);

		// Obtain a RequestDispatcher for the target resource (typically a JSP).
		RequestDispatcher rd = getRequestDispatcher(requestToExpose, dispatcherPath);
		if (rd == null) {
			throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
					"]: Check that the corresponding file exists within your web application archive!");
		}

		// If already included or response already committed, perform include, else forward.
		if (useInclude(requestToExpose, response)) {
			response.setContentType(getContentType());
			if (logger.isDebugEnabled()) {
				logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
			}
			rd.include(requestToExpose, response);
		}

		else {
			// Note: The forwarded resource is supposed to determine the content type itself.
			if (logger.isDebugEnabled()) {
				logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
			}
			rd.forward(requestToExpose, response);
		}
	}

7 在finally块中执行拦截器的applyAfterConcurrentHandlingStarted方法

if (asyncManager.isConcurrentHandlingStarted()){
    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
    return;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值