zoukankan      html  css  js  c++  java
  • SpringMVC源码解析-HTTP请求处理和分发

    1.HandlerMapping的配置和设计

        在初始化完成时,所有的handlerMapping都已经被加载,handlerMapping存储着HTTP请求对应的映射数据,每一个handlerMapping持有从URL请求到Controller的映射。

    这里以SimpleUrlHandlerMapping为例来分析它的设计与实现。在SimpleUrlHandlerMapping中,定义了一个map来维持映射关系,即URL请求和控制器对应关系,

    是SpringMVC应用可以根据HTTP请求确定对一个对应的Controller,具体来说,这些映射关系是通过接口类HandlerMapping来封装,在HandlerMapping接口中定义了一个getHandler方法,

    通过这个方法,可以获得与HTTP请求对应的HandlerExecutionChain,在这个HandlerExecutionChain中,封装具体的Controller对象。

    SimpleUrlHandlerMapping中的urlMap:

    public class SimpleUrlHandlerMapping extends AbstractUrlHandlerMapping {
           //url和controller映射的map
    	private final Map<String, Object> urlMap = new HashMap<String, Object>();
    

    HandlerMapping中的getHandler

    public interface HandlerMapping {
            //省略。。。
               
    	HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
    
    }
    

     接下来,看一下HandlerExecutionChain的实现。

    public class HandlerExecutionChain {
    
    	private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
    
    	private final Object handler;//处理对象,也就是controller对象
    
    	private HandlerInterceptor[] interceptors;//拦截器
    
    	private List<HandlerInterceptor> interceptorList;//拦截器
    
    	private int interceptorIndex = -1;
    
    
    	/**
    	 * Create a new HandlerExecutionChain.
    	 * @param handler the handler object to execute
    	 */
    	public HandlerExecutionChain(Object handler) {
    		this(handler, (HandlerInterceptor[]) null);
    	}
    
    	/**
    	 * Create a new HandlerExecutionChain.
    	 * @param handler the handler object to execute
    	 * @param interceptors the array of interceptors to apply
    	 * (in the given order) before the handler itself executes
    	 *///初始化
    	public HandlerExecutionChain(Object handler, HandlerInterceptor... interceptors) {
    		if (handler instanceof HandlerExecutionChain) {
    			HandlerExecutionChain originalChain = (HandlerExecutionChain) handler;
    			this.handler = originalChain.getHandler();
    			this.interceptorList = new ArrayList<HandlerInterceptor>();
    			CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList);
    			CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList);
    		}
    		else {
    			this.handler = handler;
    			this.interceptors = interceptors;
    		}
    	}
    
    
    	/**
    	 * Return the handler object to execute.
    	 * @return the handler object
    	 *///获取handler,本质就是controller对象
    	public Object getHandler() {
    		return this.handler;
    	}
        //添加拦截器
    	public void addInterceptor(HandlerInterceptor interceptor) {
    		initInterceptorList().add(interceptor);
    	}
           //添加多个拦截器
    	public void addInterceptors(HandlerInterceptor... interceptors) {
    		if (!ObjectUtils.isEmpty(interceptors)) {
    			initInterceptorList().addAll(Arrays.asList(interceptors));
    		}
    	}
    
    	private List<HandlerInterceptor> initInterceptorList() {
    		if (this.interceptorList == null) {
    			this.interceptorList = new ArrayList<HandlerInterceptor>();
    			if (this.interceptors != null) {
    				// An interceptor array specified through the constructor
    				this.interceptorList.addAll(Arrays.asList(this.interceptors));
    			}
    		}
    		this.interceptors = null;
    		return this.interceptorList;
    	}
    
    	/**
    	 * Return the array of interceptors to apply (in the given order).
    	 * @return the array of HandlerInterceptors instances (may be {@code null})
    	 */
    	public HandlerInterceptor[] getInterceptors() {
    		if (this.interceptors == null && this.interceptorList != null) {
    			this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[this.interceptorList.size()]);
    		}
    		return this.interceptors;
    	}
    
    
    	/**
    	 * Apply preHandle methods of registered interceptors.
    	 * @return {@code true} if the execution chain should proceed with the
    	 * next interceptor or the handler itself. Else, DispatcherServlet assumes
    	 * that this interceptor has already dealt with the response itself.
    	 *///执行之前调用拦截器
    	boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    		HandlerInterceptor[] interceptors = getInterceptors();
    		if (!ObjectUtils.isEmpty(interceptors)) {
    			for (int i = 0; i < interceptors.length; i++) {
    				HandlerInterceptor interceptor = interceptors[i];
    				if (!interceptor.preHandle(request, response, this.handler)) {
    					triggerAfterCompletion(request, response, null);
    					return false;
    				}
    				this.interceptorIndex = i;
    			}
    		}
    		return true;
    	}
    
    	/**
    	 * Apply postHandle methods of registered interceptors.
    	 *///执行之后调用拦截器
    	void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
    		HandlerInterceptor[] interceptors = getInterceptors();
    		if (!ObjectUtils.isEmpty(interceptors)) {
    			for (int i = interceptors.length - 1; i >= 0; i--) {
    				HandlerInterceptor interceptor = interceptors[i];
    				interceptor.postHandle(request, response, this.handler, mv);
    			}
    		}
    	}
    
    	/**
    	 * Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
    	 * Will just invoke afterCompletion for all interceptors whose preHandle invocation
    	 * has successfully completed and returned true.
    	 *///调用拦截器的afterCompletion方法
    	void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
    			throws Exception {
    
    		HandlerInterceptor[] interceptors = getInterceptors();
    		if (!ObjectUtils.isEmpty(interceptors)) {
    			for (int i = this.interceptorIndex; i >= 0; i--) {
    				HandlerInterceptor interceptor = interceptors[i];
    				try {
    					interceptor.afterCompletion(request, response, this.handler, ex);
    				}
    				catch (Throwable ex2) {
    					logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
    				}
    			}
    		}
    	}
    
    	/**
    	 * Apply afterConcurrentHandlerStarted callback on mapped AsyncHandlerInterceptors.
    	 */
    	void applyAfterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response) {
    		HandlerInterceptor[] interceptors = getInterceptors();
    		if (!ObjectUtils.isEmpty(interceptors)) {
    			for (int i = interceptors.length - 1; i >= 0; i--) {
    				if (interceptors[i] instanceof AsyncHandlerInterceptor) {
    					try {
    						AsyncHandlerInterceptor asyncInterceptor = (AsyncHandlerInterceptor) interceptors[i];
    						asyncInterceptor.afterConcurrentHandlingStarted(request, response, this.handler);
    					}
    					catch (Throwable ex) {
    						logger.error("Interceptor [" + interceptors[i] + "] failed in afterConcurrentHandlingStarted", ex);
    					}
    				}
    			}
    		}
    	}
    
    
    	/**
    	 * Delegates to the handler's {@code toString()}.
    	 */
    	@Override
    	public String toString() {
    		if (this.handler == null) {
    			return "HandlerExecutionChain with no handler";
    		}
    		StringBuilder sb = new StringBuilder();
    		sb.append("HandlerExecutionChain with handler [").append(this.handler).append("]");
    		if (!CollectionUtils.isEmpty(this.interceptorList)) {
    			sb.append(" and ").append(this.interceptorList.size()).append(" interceptor");
    			if (this.interceptorList.size() > 1) {
    				sb.append("s");
    			}
    		}
    		return sb.toString();
    	}
    
    }
    

     下面是拦截器的执行图

    对应的applyPreHandle和applyPostHandle方法代码如下:

    /**
    	 * Apply preHandle methods of registered interceptors.
    	 * @return {@code true} if the execution chain should proceed with the
    	 * next interceptor or the handler itself. Else, DispatcherServlet assumes
    	 * that this interceptor has already dealt with the response itself.
    	 */
    	boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    		HandlerInterceptor[] interceptors = getInterceptors();
    		if (!ObjectUtils.isEmpty(interceptors)) {
    			for (int i = 0; i < interceptors.length; i++) {
    				HandlerInterceptor interceptor = interceptors[i];
    				if (!interceptor.preHandle(request, response, this.handler)) {
    					triggerAfterCompletion(request, response, null);
    					return false;
    				}
    				this.interceptorIndex = i;
    			}
    		}
    		return true;
    	}
    
    	/**
    	 * Apply postHandle methods of registered interceptors.
    	 */
    	void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
    		HandlerInterceptor[] interceptors = getInterceptors();
    		if (!ObjectUtils.isEmpty(interceptors)) {
    			for (int i = interceptors.length - 1; i >= 0; i--) {
    				HandlerInterceptor interceptor = interceptors[i];
    				interceptor.postHandle(request, response, this.handler, mv);
    			}
    		}
    	}
    

      回到SimpleUrlHandlerMapping中,有一个initApplicationContext方法

    /**
    	 * Calls the {@link #registerHandlers} method in addition to the
    	 * superclass's initialization.
    	 */
    	@Override
    	public void initApplicationContext() throws BeansException {
    		super.initApplicationContext();
    		registerHandlers(this.urlMap);
    	}
    

      继续看看registerHandlers方法,注册Handler

    protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {
    		if (urlMap.isEmpty()) {
    			logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");
    		}
    		else {
    			for (Map.Entry<String, Object> entry : urlMap.entrySet()) {
    				String url = entry.getKey();
    				Object handler = entry.getValue();
    				// Prepend with slash if not already present.
    				if (!url.startsWith("/")) {//不是以"/"开头的,加上"/"
    					url = "/" + url;
    				}
    				// Remove whitespace from handler bean name.
    				if (handler instanceof String) {
    					handler = ((String) handler).trim();
    				}
    				registerHandler(url, handler);
    			}
    		}
    	}
    

      AbstractUrlHandlerMapping对handler的注册

    /**
    	 * Register the specified handler for the given URL path.
    	 * @param urlPath the URL the bean should be mapped to
    	 * @param handler the handler instance or handler bean name String
    	 * (a bean name will automatically be resolved into the corresponding handler bean)
    	 * @throws BeansException if the handler couldn't be registered
    	 * @throws IllegalStateException if there is a conflicting handler registered
    	 */
    	protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
    		Assert.notNull(urlPath, "URL path must not be null");
    		Assert.notNull(handler, "Handler object must not be null");
    		Object resolvedHandler = handler;
    
    		// Eagerly resolve handler if referencing singleton via name.
    		if (!this.lazyInitHandlers && handler instanceof String) {
    			String handlerName = (String) handler;
    			if (getApplicationContext().isSingleton(handlerName)) {
    				resolvedHandler = getApplicationContext().getBean(handlerName);//直接从spring容器中获取handler
    			}
    		}
    
    		Object mappedHandler = this.handlerMap.get(urlPath);//从map中获取handler
    		if (mappedHandler != null) {
    			if (mappedHandler != resolvedHandler) {
    				throw new IllegalStateException(
    						"Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
    						"]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
    			}
    		}
    		else {
    			if (urlPath.equals("/")) {
    				if (logger.isInfoEnabled()) {
    					logger.info("Root mapping to " + getHandlerDescription(handler));
    				}
    				setRootHandler(resolvedHandler);//url是"/",将其设置为根handler
    			}
    			else if (urlPath.equals("/*")) {
    				if (logger.isInfoEnabled()) {
    					logger.info("Default mapping to " + getHandlerDescription(handler));
    				}
    				setDefaultHandler(resolvedHandler);//默认handler
    			}
    			else {
    				this.handlerMap.put(urlPath, resolvedHandler);//注册handler,url为key,controller为value的map
    				if (logger.isInfoEnabled()) {
    					logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler));
    				}
    			}
    		}
    	}
    

      有了上面的配置好了Url和Controller的映射关系,为SpringMVC响应HTTP请求准备好了基础的映射数据,至此SpringMVC就可以等待HTTP的请求的到来。

    2.使用HandlerMapping完成请求的映射处理

    当请求来时,首先AbstractHandlerMapping的getHandler被调用,方法参数是request

    @Override
    	public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    		Object handler = getHandlerInternal(request);
    		if (handler == null) {//为空走默认的handler
    			handler = getDefaultHandler();
    		}
    		if (handler == null) {
    			return null;
    		}
    		// Bean name or resolved handler?
    		if (handler instanceof String) {
    			String handlerName = (String) handler;//从spring容器中获取
    			handler = getApplicationContext().getBean(handlerName);
    		}
    		return getHandlerExecutionChain(handler, request);//把handler封装到HandlerExecutionChain中并加上拦截器
    	}
    

      封装HandlerExecutionChain

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

      上面的getHnadler会调用getHandlerInternal

    protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
    		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    		Object handler = lookupHandler(lookupPath, request);
    		if (handler == null) {
    			// We need to care for the default handler directly, since we need to
    			// expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
    			Object rawHandler = null;
    			if ("/".equals(lookupPath)) {
    				rawHandler = getRootHandler();
    			}
    			if (rawHandler == null) {
    				rawHandler = getDefaultHandler();
    			}
    			if (rawHandler != null) {
    				// Bean name or resolved handler?
    				if (rawHandler instanceof String) {
    					String handlerName = (String) rawHandler;
    					rawHandler = getApplicationContext().getBean(handlerName);
    				}
    				validateHandler(rawHandler, request);
    				handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
    			}
    		}
    		if (handler != null && logger.isDebugEnabled()) {
    			logger.debug("Mapping [" + lookupPath + "] to " + handler);
    		}
    		else if (handler == null && logger.isTraceEnabled()) {
    			logger.trace("No handler mapping found for [" + lookupPath + "]");
    		}
    		return handler;
    	}
    

      这里调用的是lookupHandler方法,在来看一下这个方法。

    protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
    		// Direct match?
    		Object handler = this.handlerMap.get(urlPath);
    		if (handler != null) {
    			// Bean name or resolved handler?
    			if (handler instanceof String) {
    				String handlerName = (String) handler;
    				handler = getApplicationContext().getBean(handlerName);
    			}
    			validateHandler(handler, request);
    			return buildPathExposingHandler(handler, urlPath, urlPath, null);
    		}
    		// Pattern match?
    		List<String> matchingPatterns = new ArrayList<String>();
    		for (String registeredPattern : this.handlerMap.keySet()) {
    			if (getPathMatcher().match(registeredPattern, urlPath)) {
    				matchingPatterns.add(registeredPattern);
    			}
    		}
    		String bestPatternMatch = null;
    		Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);
    		if (!matchingPatterns.isEmpty()) {
    			Collections.sort(matchingPatterns, patternComparator);
    			if (logger.isDebugEnabled()) {
    				logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns);
    			}
    			bestPatternMatch = matchingPatterns.get(0);
    		}
    		if (bestPatternMatch != null) {
    			handler = this.handlerMap.get(bestPatternMatch);
    			// Bean name or resolved handler?
    			if (handler instanceof String) {
    				String handlerName = (String) handler;
    				handler = getApplicationContext().getBean(handlerName);
    			}
    			validateHandler(handler, request);
    			String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPatternMatch, urlPath);
    
    			// There might be multiple 'best patterns', let's make sure we have the correct URI template variables
    			// for all of them
    			Map<String, String> uriTemplateVariables = new LinkedHashMap<String, String>();
    			for (String matchingPattern : matchingPatterns) {
    				if (patternComparator.compare(bestPatternMatch, matchingPattern) == 0) {
    					Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);
    					Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars);
    					uriTemplateVariables.putAll(decodedVars);
    				}
    			}
    			if (logger.isDebugEnabled()) {
    				logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables);
    			}
    			return buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables);
    		}
    		// No handler found...
    		return null;
    	}
    

      经过一系列的对HTTP请求进行解析和匹配handler的过程,得到了与请求对应的处理器。在返回handler中,已经完成了对HandlerExecutionChain进行封装工作,为HTTP请求响应做准备。

    3.SpringMVC对HTTP请求的分发处理

    回到DispatcherServlet中,对HTTP的请求是在doService中,DispatcherServlet是HttpServlet的子类,和其他Servlet一样,通过doService来响应HTTP请求。doService直接调用的是doDispatch方法

    主要看一下这个方法。

    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);//获取handler
    				if (mappedHandler == null || mappedHandler.getHandler() == null) {
    					noHandlerFound(processedRequest, response);
    					return;
    				}
    
    				// Determine handler adapter for the current request.//获取adapter
    				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;
    				}
    
    				// Actually invoke the handler.handler处理的结果封装到mv中
    				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    
    				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
    				if (mappedHandler != null) {
    					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
    				}
    			}
    			else {
    				// Clean up any resources used by a multipart request.
    				if (multipartRequestParsed) {
    					cleanupMultipart(processedRequest);
    				}
    			}
    		}
    	}
    

      看一下getHandlerAdapter方法

    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    		for (HandlerAdapter ha : this.handlerAdapters) {
    			if (logger.isTraceEnabled()) {
    				logger.trace("Testing handler adapter [" + ha + "]");
    			}
    			if (ha.supports(handler)) {//判断是否支持
    				return ha;
    			}
    		}
    		throw new ServletException("No adapter for handler [" + handler +
    				"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    	}
    

     继续看一下supports方法的实现,以SimpleControlerHandlerAdapter类为例

    public class SimpleControllerHandlerAdapter implements HandlerAdapter {
    
    	@Override
    	public boolean supports(Object handler) {
    		return (handler instanceof Controller);
    	}
    
    	@Override
    	public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
    			throws Exception {
    
    		return ((Controller) handler).handleRequest(request, response);
    	}
    
    	@Override
    	public long getLastModified(HttpServletRequest request, Object handler) {
    		if (handler instanceof LastModified) {
    			return ((LastModified) handler).getLastModified(request);
    		}
    		return -1L;
    	}
    
    }
    

      经过上面一系列的操作,得到handler对象,handler调用handleRequest方法,返回ModelAndView对象,最后通过render方法进行渲染。

    问题:handlerMapping是在什么时候初始化的?

    在DispatcherServlet调用init->initStrategies方法中,进行初始化。

    protected void initStrategies(ApplicationContext context) {
    		initMultipartResolver(context);
    		initLocaleResolver(context);
    		initThemeResolver(context);
                   //初始化handlerMapping
    		initHandlerMappings(context);
    		initHandlerAdapters(context);
    		initHandlerExceptionResolvers(context);
    		initRequestToViewNameTranslator(context);
    		initViewResolvers(context);
    		initFlashMapManager(context);
    	}
    

      最后一个请求的流程图。

     

     

     

      

  • 相关阅读:
    利用ganymed-ssh2远程执行其它Linux机器上的shell命令
    ZooKeeper 笔记(4) 实战应用之【消除单点故障】
    ZooKeeper 笔记(3) 实战应用之【统一配置管理】
    ZooKeeper 笔记(2) 监听数据变化
    ZooKeeper 笔记(1) 安装部署及hello world
    intellij idea 高级用法之:集成JIRA、UML类图插件、集成SSH、集成FTP、Database管理
    hadoop: hive 1.2.0 在mac机上的安装与配置
    mac 下卸载mysql的方法
    mac OS X Yosemite 上编译hadoop 2.6.0/2.7.0及TEZ 0.5.2/0.7.0 注意事项
    hadoop: hbase1.0.1.1 伪分布安装
  • 原文地址:https://www.cnblogs.com/lzeffort/p/7860646.html
Copyright © 2011-2022 走看看