zoukankan      html  css  js  c++  java
  • SpringMVC源码阅读(一)

    DispatcherServlet是整个SpringMVC初始化和处理请求的重要类,作为一个servlet,拥有

    public void init(ServletConfig config) throws ServletException;
    
    public ServletConfig getServletConfig();
    
    public void service(ServletRequest req, ServletResponse res)
    throws ServletException, IOException;
    
     public String getServletInfo();
    
     public void destroy();
    

      

    这些基础方法和其他扩展方法。

    init  service destroy 方法  

    <servlet>
    	<servlet-name>springMVC</servlet-name>
    	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    
    	<!-- 可以自定义servlet.xml配置文件的位置和名称,默认为WEB-INF目录下,名称为[<servlet-name>]- servlet.xml,如spring-servlet.xml -->
    	<init-param>
    		<param-name>contextConfigLocation</param-name>
    		<param-value>classpath*:config/spring-servlet.xml</param-value>
    	</init-param>
    
    	<load-on-startup>1</load-on-startup>
    </servlet>
    
    <servlet-mapping>
    		<servlet-name>springMVC</servlet-name>
    		<url-pattern>/</url-pattern>
    </servlet-mapping>
    

    下面重点分析DispatcherServlet这个类

    --------------------------------

    我们可以看到org.springframework.web.servlet.DispatcherServlet类继承了FrameworkServlet类

    public class DispatcherServlet extends FrameworkServlet
    

    org.springframework.web.servlet.FrameworkServlet类继承了HttpServletBean类 而HttpServletBean类又继承了HttpServlet类(该类属于servlet-api了)

    public abstract class FrameworkServlet extends HttpServletBean
    public abstract class HttpServletBean extends HttpServlet 
    

     javax.servlet.http.HttpServlet类    org.springframework.web.servlet.HttpServletBean类  org.springframework.web.servlet.FrameworkServlet类

       org.springframework.web.servlet.DispatcherServlet类

       下面我们看servlet的处理请求的过程 重写的doGet doPost方法在FrameworkServlet当中

    /**
    	 * Delegate GET requests to processRequest/doService.
    	 * <p>Will also be invoked by HttpServlet's default implementation of <code>doHead</code>,
    	 * with a <code>NoBodyResponse</code> that just captures the content length.
    	 * @see #doService
    	 * @see #doHead
    	 */
    	@Override
    	protected final void doGet(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    
    		processRequest(request, response);
    	}
    
    /**
    	 * Delegate POST requests to {@link #processRequest}.
    	 * @see #doService
    	 */
    	@Override
    	protected final void doPost(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    
    		processRequest(request, response);
    	}
    

    他们都调用了processRequest(request,response)方法,该方法仍在FrameworkServlet当中

    /**
    	 * Process this request, publishing an event regardless of the outcome.
    	 * <p>The actual event handling is performed by the abstract
    	 * {@link #doService} template method.
    	 */
    	protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    
    		long startTime = System.currentTimeMillis();
    		Throwable failureCause = null;
    
    		// Expose current LocaleResolver and request as LocaleContext.
    		LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
    		LocaleContextHolder.setLocaleContext(buildLocaleContext(request), this.threadContextInheritable);
    
    		// Expose current RequestAttributes to current thread.
    		RequestAttributes previousRequestAttributes = RequestContextHolder.getRequestAttributes();
    		ServletRequestAttributes requestAttributes = null;
    		if (previousRequestAttributes == null || previousRequestAttributes.getClass().equals(ServletRequestAttributes.class)) {
    			requestAttributes = new ServletRequestAttributes(request);
    			RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
    		}
    
    		if (logger.isTraceEnabled()) {
    			logger.trace("Bound request context to thread: " + request);
    		}
    
    		try {
    			doService(request, response);
    		}
    		catch (ServletException ex) {
    			failureCause = ex;
    			throw ex;
    		}
    		catch (IOException ex) {
    			failureCause = ex;
    			throw ex;
    		}
    		catch (Throwable ex) {
    			failureCause = ex;
    			throw new NestedServletException("Request processing failed", ex);
    		}
    
    		finally {
    			// Clear request attributes and reset thread-bound context.
    			LocaleContextHolder.setLocaleContext(previousLocaleContext, this.threadContextInheritable);
    			if (requestAttributes != null) {
    				RequestContextHolder.setRequestAttributes(previousRequestAttributes, this.threadContextInheritable);
    				requestAttributes.requestCompleted();
    			}
    			if (logger.isTraceEnabled()) {
    				logger.trace("Cleared thread-bound request context: " + request);
    			}
    
    			if (failureCause != null) {
    				this.logger.debug("Could not complete request", failureCause);
    			}
    			else {
    				this.logger.debug("Successfully completed request");
    			}
    			if (this.publishEvents) {
    				// Whether or not we succeeded, publish an event.
    				long processingTime = System.currentTimeMillis() - startTime;
    				this.webApplicationContext.publishEvent(
    						new ServletRequestHandledEvent(this,
    								request.getRequestURI(), request.getRemoteAddr(),
    								request.getMethod(), getServletConfig().getServletName(),
    								WebUtils.getSessionId(request), getUsernameForRequest(request),
    								processingTime, failureCause));
    			}
    		}
    	}
    

    对于该processRequest当中的其他方法暂时撇开不谈,看看其中的处理方法

    doService(request,response)

    /**
    	 * Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}
    	 * for the actual dispatching.
    	 */
    	@Override
    	protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    		if (logger.isDebugEnabled()) {
    			String requestUri = urlPathHelper.getRequestUri(request);
    			logger.debug("DispatcherServlet with name '" + getServletName() + "' processing " + request.getMethod() +
    					" request for [" + requestUri + "]");
    		}
    
    		// Keep a snapshot of the request attributes in case of an include,
    		// to be able to restore the original attributes after the include.
    		Map<String, Object> attributesSnapshot = null;
    		if (WebUtils.isIncludeRequest(request)) {
    			logger.debug("Taking snapshot of request attributes before include");
    			attributesSnapshot = new HashMap<String, Object>();
    			Enumeration attrNames = request.getAttributeNames();
    			while (attrNames.hasMoreElements()) {
    				String attrName = (String) attrNames.nextElement();
    				if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
    					attributesSnapshot.put(attrName, request.getAttribute(attrName));
    				}
    			}
    		}
    
    		// Make framework objects available to handlers and view objects.
    		request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
    		request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
    		request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
    		request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
    
    		try {
    			doDispatch(request, response);
    		}
    		finally {
    			// Restore the original attribute snapshot, in case of an include.
    			if (attributesSnapshot != null) {
    				restoreAttributesAfterInclude(request, attributesSnapshot);
    			}
    		}
    	}
    

    负责将初始化好的framework的context放置进request当中方便后续处理

    // Make framework objects available to handlers and view objects.
    request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
    request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
    request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
    request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
    

     

    下面看doDispatch(request,reponse)方法,也是在DispatcherServlet类当中

    /**
    	 * 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;
    		int interceptorIndex = -1;
    
    		try {
    			ModelAndView mv;
    			boolean errorView = false;
    
    			try {
    				processedRequest = checkMultipart(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()) {
    						String requestUri = urlPathHelper.getRequestUri(request);
    						logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
    					}
    					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
    						return;
    					}
    				}
    
    				// 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;
    					}
    				}
    
    				// Actually invoke the handler.
    				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    
    				// Do we need view name translation?
    				if (mv != null && !mv.hasView()) {
    					mv.setViewName(getDefaultViewName(request));
    				}
    
    				// Apply postHandle methods of registered interceptors.
    				if (interceptors != null) {
    					for (int i = interceptors.length - 1; i >= 0; i--) {
    						HandlerInterceptor interceptor = interceptors[i];
    						interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);
    					}
    				}
    			}
    			catch (ModelAndViewDefiningException ex) {
    				logger.debug("ModelAndViewDefiningException encountered", ex);
    				mv = ex.getModelAndView();
    			}
    			catch (Exception ex) {
    				Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
    				mv = processHandlerException(processedRequest, response, handler, ex);
    				errorView = (mv != null);
    			}
    
    			// Did the handler return a view to render?
    			if (mv != null && !mv.wasCleared()) {
    				render(mv, processedRequest, response);
    				if (errorView) {
    					WebUtils.clearErrorRequestAttributes(request);
    				}
    			}
    			else {
    				if (logger.isDebugEnabled()) {
    					logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
    							"': assuming HandlerAdapter completed request handling");
    				}
    			}
    
    			// Trigger after-completion for successful outcome.
    			triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
    		}
    
    		catch (Exception ex) {
    			// Trigger after-completion for thrown exception.
    			triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
    			throw ex;
    		}
    		catch (Error err) {
    			ServletException ex = new NestedServletException("Handler processing failed", err);
    			// Trigger after-completion for thrown exception.
    			triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
    			throw ex;
    		}
    
    		finally {
    			// Clean up any resources used by a multipart request.
    			if (processedRequest != request) {
    				cleanupMultipart(processedRequest);
    			}
    		}
    	}
    

    下面分析上面的这个方法

    HandlerExecutionChain mappedHandler = null;
    .........
    ........
    // Determine handler for the current request.
    mappedHandler = getHandler(processedRequest, false);
    

     

    /**
    	 * 返回request请求对应的 HandlerExecutionChain 对象. 按照顺序遍历所有的handler mapping
    	 * @param request current HTTP request
    	 * @param cache whether to cache the HandlerExecutionChain in a request attribute
    	 * @return the HandlerExecutionChain, or <code>null</code> if no handler could be found
    	 * @deprecated as of Spring 3.0.4, in favor of {@link #getHandler(javax.servlet.http.HttpServletRequest)},
    	 * with this method's cache attribute now effectively getting ignored
    	 */
    	@Deprecated
    	protected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache) throws Exception {
    		return getHandler(request);
    	}
    

    真正执行遍历的方法,仍然在DispatcherServlet类当中

    /**
    	 * Return the HandlerExecutionChain for this request.
    	 * <p>Tries all handler mappings in order.
    	 * @param request current HTTP request
    	 * @return the HandlerExecutionChain, or <code>null</code> 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;
    	}
    

      

     我们看到HandlerExectionChain类是通过HandlerMapping类的gatHandler(HttpServletRequest request)方法创建的  HandlerMapping是个接口,三个常量,一个方法

    package org.springframework.web.servlet;
    
    import javax.servlet.http.HttpServletRequest;
    
    /**
     * Interface to be implemented by objects that define a mapping between
     * requests and handler objects.
     *
     * <p>This class can be implemented by application developers, although this is not
     * necessary, as {@link org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping}
     * and {@link org.springframework.web.servlet.handler.SimpleUrlHandlerMapping}
     * are included in the framework. The former is the default if no
     * HandlerMapping bean is registered in the application context.
     *
     * <p>HandlerMapping implementations can support mapped interceptors but do not
     * have to. A handler will always be wrapped in a {@link HandlerExecutionChain}
     * instance, optionally accompanied by some {@link HandlerInterceptor} instances.
     * The DispatcherServlet will first call each HandlerInterceptor's
     * <code>preHandle</code> method in the given order, finally invoking the handler
     * itself if all <code>preHandle</code> methods have returned <code>true</code>.
     *
     * <p>The ability to parameterize this mapping is a powerful and unusual
     * capability of this MVC framework. For example, it is possible to write
     * a custom mapping based on session state, cookie state or many other
     * variables. No other MVC framework seems to be equally flexible.
     *
     * <p>Note: Implementations can implement the {@link org.springframework.core.Ordered}
     * interface to be able to specify a sorting order and thus a priority for getting
     * applied by DispatcherServlet. Non-Ordered instances get treated as lowest priority.
     *
     * @author Rod Johnson
     * @author Juergen Hoeller
     * @see org.springframework.core.Ordered
     * @see org.springframework.web.servlet.handler.AbstractHandlerMapping
     * @see org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
     * @see org.springframework.web.servlet.handler.SimpleUrlHandlerMapping
     */
    public interface HandlerMapping {
    
    	/**
    	 * Name of the {@link HttpServletRequest} attribute that contains the path
    	 * within the handler mapping, in case of a pattern match, or the full
    	 * relevant URI (typically within the DispatcherServlet's mapping) else.
    	 * <p>Note: This attribute is not required to be supported by all
    	 * HandlerMapping implementations. URL-based HandlerMappings will
    	 * typically support it, but handlers should not necessarily expect
    	 * this request attribute to be present in all scenarios.
    	 */
    	String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";
    
    	/**
    	 * Name of the {@link HttpServletRequest} attribute that contains the
    	 * best matching pattern within the handler mapping.
    	 * <p>Note: This attribute is not required to be supported by all
    	 * HandlerMapping implementations. URL-based HandlerMappings will
    	 * typically support it, but handlers should not necessarily expect
    	 * this request attribute to be present in all scenarios.
    	 */
    	String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern";
    
    	/**
    	 * Name of the {@link HttpServletRequest} attribute that contains the URI
    	 * templates map, mapping variable names to values.
    	 * <p>Note: This attribute is not required to be supported by all
    	 * HandlerMapping implementations. URL-based HandlerMappings will
    	 * typically support it, but handlers should not necessarily expect
    	 * this request attribute to be present in all scenarios.
    	 */
    	String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables";
    
    	/**
    	 * Return a handler and any interceptors for this request. The choice may be made
    	 * on request URL, session state, or any factor the implementing class chooses.
    	 * <p>The returned HandlerExecutionChain contains a handler Object, rather than
    	 * even a tag interface, so that handlers are not constrained in any way.
    	 * For example, a HandlerAdapter could be written to allow another framework's
    	 * handler objects to be used.
    	 * <p>Returns <code>null</code> if no match was found. This is not an error.
    	 * The DispatcherServlet will query all registered HandlerMapping beans to find
    	 * a match, and only decide there is an error if none can find a handler.
    	 * @param request current HTTP request
    	 * @return a HandlerExecutionChain instance containing handler object and
    	 * any interceptors, or <code>null</code> if no mapping found
    	 * @throws Exception if there is an internal error
    	 */
    	HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
    
    }
    

    我们重点关注的HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception方法只有一个实现者,在

    AbstractHandlerMapping类当中

    /**
    	 * 为参数request查找对应的handler, 查找失败则返回默认的handler
    	 * @param request current HTTP request
    	 * @return the corresponding handler instance, or the default handler
    	 * @see #getHandlerInternal
    	 */
    	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);
    	}
    

     Abstract当中的getHandlerExecutionChain方法

      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;
      }
    

      

    继续返回doDispatcher方法,获得了HandlerExecutionChain之后,构造了一个HandlerAdapter

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

    最后我们发现是通过HandlerAdapter的handle方法产生的ModelAndView

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

      

  • 相关阅读:
    异常处理
    JPG转换成BMP不成功???
    Vmware 7 下装载的最新Ubuntu10.04镜像会出现无法识别键盘输入的解决方法
    动态IP获取
    最佳Web设计资源
    设置NFS
    Ubuntu设置root用户自动登录
    编译QT4.5
    tq2440修改默认串口不支持打印控制台
    英语作文
  • 原文地址:https://www.cnblogs.com/wuxinliulei/p/5061220.html
Copyright © 2011-2022 走看看