首先, 如果我们想在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;
- }
- 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);
- }
- <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);
- }
获得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>
总结如图:
另外应该注意的是,我们若想使用Spring MVC, 就必须有一个类似于Spring的applicationContext.xml那样的配置文件,(默认名为servletName-servlet.xml, 这里的servletName指在web.xml中配置的servlet的name属性)配置文件,。作用不用多说,与Spring的applicationContext.xml类似,作为IOC容器的核心文件, 所有bean组件都通过它来创建。也是IOC的核心。