SpringMVC原始碼解析(下)

potato123發表於2009-05-22

4.請求-處理鏈對映(HandlerMapping)
   HandlerMapping定義了請求與處理鏈之間的對映的策略,見如下介面。

   public interface HandlerMapping {
    String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";

    HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}

   主要的繼承類和繼承結構如下

   其中
*AbstractHandlerMapping:定義了HandlerMapping實現的最基礎的部分內容,包括攔截器列表和預設處理物件
*AbstractUrlHandlerMapping:在AbstractHandlerMapping的基礎上,定義了從URL到處理物件的對映關係管理,其主要處理過程如下
   getHandlerInternal:

	protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
		String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
		if (logger.isDebugEnabled()) {
			logger.debug("Looking up handler for [" + lookupPath + "]");
		}
		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) {
				validateHandler(rawHandler, request);
				handler = buildPathExposingHandler(rawHandler, lookupPath);
			}
		}
		return handler;
	}

 

   lookupHandler:

	protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
		// Direct match?
		Object handler = this.handlerMap.get(urlPath);
		if (handler != null) {
			validateHandler(handler, request);
			return buildPathExposingHandler(handler, urlPath);
		}
		// Pattern match?
		String bestPathMatch = null;
		for (Iterator it = this.handlerMap.keySet().iterator(); it.hasNext();) {
			String registeredPath = (String) it.next();
			if (getPathMatcher().match(registeredPath, urlPath) &&
					(bestPathMatch == null || bestPathMatch.length() < registeredPath.length())) {
				bestPathMatch = registeredPath;
			}
		}
		if (bestPathMatch != null) {
			handler = this.handlerMap.get(bestPathMatch);
			validateHandler(handler, request);
			String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPathMatch, urlPath);
			return buildPathExposingHandler(handler, pathWithinMapping);
		}
		// No handler found...
		return null;
	}

 另外,其定義了Handler的註冊方法registerHandler

*AbstractDetectingUrlHandlerMapping:AbstractDetectingUrlHandlerMapping通過繼承ApplicationObjectSupport實現了ApplicationContextAware介面,在初始化完成之後自動通過ApplicationObjectSupport.setApplicationContext-->AbstractDetectingUrlHandlerMapping.initApplicationContext-->AbstractDetectingUrlHandlerMapping.detectHandlers呼叫detectHandlers函式,該函式將註冊到ApplicationContext的所有Bean物件逐一檢查,由其子類實現的determineUrlsForHandler判斷每個Bean物件對應的URL,並將URL與Bean的關係通過AbstractUrlHandlerMapping.registerHandler註冊

	protected void detectHandlers() throws BeansException {
		if (logger.isDebugEnabled()) {
			logger.debug("Looking for URL mappings in application context: " + getApplicationContext());
		}
		String[] beanNames = (this.detectHandlersInAncestorContexts ?
				BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
				getApplicationContext().getBeanNamesForType(Object.class));

		// Take any bean name or alias that begins with a slash.
		for (int i = 0; i < beanNames.length; i++) {
			String beanName = beanNames[i];
			String[] urls = determineUrlsForHandler(beanName);
			if (!ObjectUtils.isEmpty(urls)) {
				// URL paths found: Let's consider it a handler.
				registerHandler(urls, beanName);
			}
			else {
				if (logger.isDebugEnabled()) {
					logger.debug("Rejected bean name '" + beanNames[i] + "': no URL paths identified");
				}
			}
		}
	}

 

*BeanNameUrlHandlerMapping:非常簡單,其實現determineUrlsForHandler函式,如果一個Bean以“/”開頭,則認為是一個處理器類,並且以bean的名字作為對映的url,處理過程如下

	protected String[] determineUrlsForHandler(String beanName) {
		List urls = new ArrayList();
		if (beanName.startsWith("/")) {
			urls.add(beanName);
		}
		String[] aliases = getApplicationContext().getAliases(beanName);
		for (int j = 0; j < aliases.length; j++) {
			if (aliases[j].startsWith("/")) {
				urls.add(aliases[j]);
			}
		}
		return StringUtils.toStringArray(urls);
	}

 

*DefaultAnnotationHandlerMapping:實現determineUrlsForHandler函式,檢查每個Bean物件的類或者方法有沒有RequestMapping這個Annotation,如果有,則將相應配置的URL作為該Bean對應處理的URL,處理過程如下

protected String[] determineUrlsForHandler(String beanName) {
		ApplicationContext context = getApplicationContext();
		Class<?> handlerType = context.getType(beanName);
		RequestMapping mapping = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);

		if (mapping == null && context instanceof ConfigurableApplicationContext &&
				context.containsBeanDefinition(beanName)) {
			ConfigurableApplicationContext cac = (ConfigurableApplicationContext) context;
			BeanDefinition bd = cac.getBeanFactory().getMergedBeanDefinition(beanName);
			if (bd instanceof AbstractBeanDefinition) {
				AbstractBeanDefinition abd = (AbstractBeanDefinition) bd;
				if (abd.hasBeanClass()) {
					Class<?> beanClass = abd.getBeanClass();
					mapping = AnnotationUtils.findAnnotation(beanClass, RequestMapping.class);
				}
			}
		}

		if (mapping != null) {
			// @RequestMapping found at type level
			this.cachedMappings.put(handlerType, mapping);
			Set<String> urls = new LinkedHashSet<String>();
			String[] paths = mapping.value();
			if (paths.length > 0) {
				// @RequestMapping specifies paths at type level
				for (String path : paths) {
					addUrlsForPath(urls, path);
				}
				return StringUtils.toStringArray(urls);
			}
			else {
				// actual paths specified by @RequestMapping at method level
				return determineUrlsForHandlerMethods(handlerType);
			}
		}
		else if (AnnotationUtils.findAnnotation(handlerType, Controller.class) != null) {
			// @RequestMapping to be introspected at method level
			return determineUrlsForHandlerMethods(handlerType);
		}
		else {
			return null;
		}
	}

 

5.處理器介面卡(HandlerAdapter)
   HandlerAdapter定義了處理類如何處理請求的策略,見如下介面

   public interface HandlerAdapter {
    boolean supports(Object handler);
    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
    long getLastModified(HttpServletRequest request, Object handler);
}

   通過實現特定的策略,可以靈活地將任意物件轉換成請求處理物件,主要實現包括:

1)SimpleControllerHandlerAdapter/HttpRequestHandlerAdapter/SimpleServletHandlerAdapter/ThrowawayController
   非常簡單,面向實現實現了特定介面的處理類的情形,僅僅做一個代理執行處理,看一下其中SimpleControllerHandlerAdapter的程式碼如下,其特定處理實現了Controller介面的處理類

public class SimpleControllerHandlerAdapter implements HandlerAdapter {

    public boolean supports(Object handler) {
        return (handler instanceof Controller);
    }

    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        return ((Controller) handler).handleRequest(request, response);
    }

    public long getLastModified(HttpServletRequest request, Object handler) {
        if (handler instanceof LastModified) {
            return ((LastModified) handler).getLastModified(request);
        }
        return -1L;
    }

}

 

2)AnnotationMethodHandlerAdapter
   通過配置特定的Annotation,定義了該如何注入引數、呼叫哪個方法、對返回引數如何處理,主要過程如下(AnnotationMethodHandlerAdapter.invokeHandlerMethod)

try {
            ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);
            Method handlerMethod = methodResolver.resolveHandlerMethod(request);
            ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);
            ServletWebRequest webRequest = new ServletWebRequest(request, response);
            ExtendedModelMap implicitModel = new ExtendedModelMap();

            Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
            ModelAndView mav = methodInvoker.getModelAndView(handlerMethod, result, implicitModel, webRequest);
            methodInvoker.updateSessionAttributes(
                    handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);
            return mav;
        }
        catch (NoSuchRequestHandlingMethodException ex) {
            return handleNoSuchRequestHandlingMethod(ex, request, response);
        }

*ServletHandlerMethodResolver(AnnotationMethodHandlerAdapter內部類):該類通過請求URL、請求Method和處理類的RequestMapping定義,最終確定該使用處理類的哪個方法來處理請求
*ServletHandlerMethodInvoker(AnnotationMethodHandlerAdapter內部類):檢查處理類相應處理方法的引數以及相關的Annotation配置,確定如何轉換需要的引數傳入呼叫方法,並最終呼叫返回ModelAndView
6.檢視策略(ViewResolver)
  ViewResolver定義瞭如何確定處理檢視的View物件的策略,見如下介面

public interface ViewResolver {
    View resolveViewName(String viewName, Locale locale) throws Exception;
}

相關文章