Spring MVC源码深入剖析执行流程

 Spring MVC是现在最流行的MVC框架, 很多人说它是一个优秀的框架。实质上是由于Spring MVC加入注解,注解让Spring MVC质变, 这使得开发效率得到了飞速提升。而且它本身就是Spring的一小部分,所以让就不再像Struts2那样,需要插件的支持。也就是说,它们是无缝连接的。但无论多少多么优秀的框架,它们永远都是建立在listener, servlet, filter这些服务器容器组件之上的。可见基础尤其重要。

首先, 如果我们想在Web项目中添加Spring MVC的支持,要在web.xml中配置如下代码:

<servlet>
  	<servlet-name>springMVC</servlet-name>
  	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  	<load-on-startup>1</load-on-startup>
</servlet>

其中,org.springframework.web.servlet.DispatcherServlet就是整个Spring MVC框架的切入点。与添加Struts类似。Struts是通过Filter作为切入点,而Spring MVC使用的是Servlet。原理其实是一样的,都起到拦截用户请求的作用。Filter是在服务器启动时,即生成一个实例。而Servlet若不设置load-on-startup,则为第一次访问时生成实例。DispatcherServlet需要在服务器启动时生成实例。

下面我们通过源码的来解析Spring MVC的大体流程:

//这是DispatcherServlet的定义,继承自FrameworkServlet
public class DispatcherServlet extends FrameworkServlet {
...
	protected void initStrategies(ApplicationContext context) {
		...
}

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
}
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
}
...

}

  当我们发送请求时,DispatcherServlet会进行拦截,而对于Servlet来说。service方法是处理请求的核心,但DispatcherServlet中并没有定义此方法。我们通过父类FrameworkServlet中查看:

protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		String method = request.getMethod();
		if (method.equalsIgnoreCase(RequestMethod.PATCH.name())) {
			processRequest(request, response);
		}
		else {
			super.service(request, response);
		}
	}

  processRequest(request,response)方法调用,在这个方法中,调用的了doService(request,response)。而此时doService正是上述的DispatcherServlet中的doService方法。而doService中又调用了doDispatcher方法。那么可以看出,doDispatcher就是DispatcherServlet处理核心方法。

下面为doDispatcher方法的源码:

<span style="white-space:pre">	</span>/**
	 * Process the actual dispatching to the handler.
	 * <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
	 * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
	 * to find the first that supports the handler class.
	 * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
	 * themselves to decide which methods are acceptable.
	 * @param request current HTTP request
	 * @param response current HTTP response
	 * @throws Exception in case of any kind of processing failure
	 */
	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, false);
				if (mappedHandler == null || mappedHandler.getHandler() == 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 (logger.isDebugEnabled()) {
						logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
					}
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}

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

				try {
					// Actually invoke the handler.
					mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
				}
				finally {
					if (asyncManager.isConcurrentHandlingStarted()) {
						return;
					}
				}

				applyDefaultViewName(request, mv);
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Error err) {
			triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
		}
		finally {
			if (asyncManager.isConcurrentHandlingStarted()) {
				// Instead of postHandle and afterCompletion
				mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				return;
			}
			// Clean up any resources used by a multipart request.
			if (multipartRequestParsed) {
				cleanupMultipart(processedRequest);
			}
		}
	}

  首先有几个类需要声明,ModelAndView、HandlerExecutionChain、HandlerMapping、HandlerMethod、HandlerAdapter。

 

1、HandlerMethod(org.springframework.web.method.HandlerMethod),这个类为中存放了某个bean对象和该bean对象的某个要处理的Method对象。

2、HandlerMapping,作用为通过request对象,获取对应的HandlerMethod对象。

3、HandlerExecutionChain作用为通过加入Interceptor拦截器包装HandlerMapping返回的HandlerMethod对象。让待处理的方法对象与拦截器称为一个整体,即执行链。

4、ModelAndView,顾名思义。Model即MVC的M,View即MVC的V。其对象存放的正是数据与视图信息。

5、HandlerAdapter:作用为具体处理HandlerMethod,即通过它调用某个方法。

下面分析正题:

doDispatcher方法中,首先通过getHandler方法获得handler,如下:

<span style="white-space:pre">	</span>/**
	 * Return the HandlerExecutionChain for this request.
	 * <p>Tries all handler mappings in order.
	 * @param request current HTTP request
	 * @return the HandlerExecutionChain, or {@code null} if no handler could be found
	 */
	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并调用每个HandlerMapping对象的getHandler方法,而HandlerMapping为接口,其中AbstractHandlerMapping这个抽象类中实现了HandlerMapping接口,并实现了getHandler方法,如下:

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);
	}
其中Object handler = getHandlerInternal(request);为获取HandlerMethod对象,此方法源码如下:

<span style="white-space:pre">	</span>/**
	 * Look up a handler method for the given request.
	 */
	@Override
	protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
		if (logger.isDebugEnabled()) {
			logger.debug("Looking up handler method for path " + lookupPath);
		}
		HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
		if (logger.isDebugEnabled()) {
			if (handlerMethod != null) {
				logger.debug("Returning handler method [" + handlerMethod + "]");
			}
			else {
				logger.debug("Did not find handler method for [" + lookupPath + "]");
			}
		}
		return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
	}
在获得HandlerMethod对象之后,通过getHandlerExecutionChain(handler, request)将HandlerMethod对象与Interceptor拦截器封装,成为HandlerExecutionChain的对象。这就是doDispatch方法中mappedHandler引用指向的对象的来源流程。
获得HandlerExecutionChain对象之后,可以通过这个对象获得之前封装进去的HandlerMethod对象。通过getHandler()即可。

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

而HandlerAdapter接口的具体实现类的对象为真正调用方法,即通过反射调用HandlerMethod对象中封装的某个类的实例所对应的某个方法。

// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());</span>
返回值为ModelAndView类型的对象,作用就不必多说.而在hanle方法之前和之后有这么两个方法调用:
mappedHandler.applyPreHandle(processedRequest, response)</span>
mappedHandler.applyPostHandle(processedRequest, response, mv);</span>
作用就是通过执行链中的Interceptor拦截器做拦截处理。功能与Filter相似。


总结如图:





另外应该注意的是,我们若想使用Spring MVC, 就必须有一个类似于SpringapplicationContext.xml那样的配置文件,(默认名为servletName-servlet.xml, 这里的servletName指在web.xml中配置的servletname属性)配置文件,。作用不用多说,与SpringapplicationContext.xml类似,作为IOC容器的核心文件所有bean组件都通过它来创建。也是IOC的核心。




评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值