SpringMVC原始碼解析(下)
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;
}
相關文章
- SpringMVC原始碼解析SpringMVC原始碼
- SpringMVC DispatcherServlet原始碼解析SpringMVCServlet原始碼
- SpringMVC原始碼解析(上)SpringMVC原始碼
- 深入瞭解SpringMVC原始碼解析SpringMVC原始碼
- SpringMVC原始碼解析系列2-DispatcherServletSpringMVC原始碼Servlet
- SpringMVC原始碼關於檢視解析渲染SpringMVC原始碼
- SpringMVC原始碼解析系列4-HandleAdapterSpringMVC原始碼APT
- SpringMVC原始碼解析(1)-啟動過程SpringMVC原始碼
- SpringMVC原始碼之引數解析繫結原理SpringMVC原始碼
- SpringMVC原始碼解析系列3-HandleMappingSpringMVC原始碼APP
- dva-原始碼解析-下原始碼
- 詳解HashMap原始碼解析(下)HashMap原始碼
- [原創] KCP 原始碼解析(下)原始碼
- Spring 原始碼解析一:SpringMVC 的載入機制原始碼SpringMVC
- SpringMVC原始碼分析SpringMVC原始碼
- SpringMVC原始碼分析1:SpringMVC概述SpringMVC原始碼
- SpringMVC原始碼解析 - HandlerAdater - ModelAndViewContainer上下文容器SpringMVC原始碼ViewAI
- redux-saga原始碼解析-下Redux原始碼
- SpringMVC原始碼分析原理SpringMVC原始碼
- SpringMVC系列原始碼:DispatcherServletSpringMVC原始碼Servlet
- SpringMVC檔案上傳與下載(附工程原始碼)SpringMVC原始碼
- Spring原始碼解析—— IOC預設標籤解析(下)Spring原始碼
- Myth原始碼解析系列之七- 訂單下單流程原始碼解析(參與者)原始碼
- Myth原始碼解析系列之六- 訂單下單流程原始碼解析(發起者)原始碼
- 【原始碼解析】- ArrayList原始碼解析,絕對詳細原始碼
- spark核心(下)——job任務提交原始碼解析Spark原始碼
- [原始碼解析] PyTorch 分散式(3) ----- DataParallel(下)原始碼PyTorch分散式Parallel
- springMvc原始碼學習之:spring原始碼總結SpringMVC原始碼
- SpringMVC原始碼分析2:SpringMVC設計理念與DispatcherServletSpringMVC原始碼Servlet
- springmvc工作原理及原始碼分析SpringMVC原始碼
- SpringMVC請求流程原始碼分析SpringMVC原始碼
- SpringMVC基礎原始碼分析(一)SpringMVC原始碼
- SpringMVC原始碼系列:AbstractUrlHandlerMappingSpringMVC原始碼APP
- SpringMVC原始碼分析系列(精簡)SpringMVC原始碼
- SpringMVC原始碼系列:AbstractHandlerMappingSpringMVC原始碼APP
- SpringMVC原始碼系列:HandlerMappingSpringMVC原始碼APP
- springMvc Velocity tool 原始碼分析SpringMVC原始碼
- spring原始碼深度解析— IOC 之 預設標籤解析(下)Spring原始碼