一、 Spring-MVC的對象初始化,即 bean放入context的beanFactory中。
1. 對象的初始化工作主要在org.springframework.web.servlet.FrameworkServlet類中的initServletBean方法中完成,initServletBean方法最終會調用到
org.springframework.context.support.AbstractApplicationContext類的refresh方法,refresh方法是主要的bean的初始化方法。refresh方法又調用類裡面的obtainFreshBeanFactory方法。
2. org.springframework.beans.factory.support.DefaultListableBeanFactory為默認的BeanFactory,
DefaultListableBeanFactory 類中的registerBeanDefinition方法為保存對象列表信息的主要方法,beanFactory中的對象存放到成員變量Map<String, BeanDefinition> beanDefinitionMap中。
1 private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(); 2 3 //--------------------------------------------------------------------- 4 // Implementation of BeanDefinitionRegistry interface 5 //--------------------------------------------------------------------- 6 7 public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) 8 throws BeanDefinitionStoreException { 9 10 Assert.hasText(beanName, "Bean name must not be empty"); 11 Assert.notNull(beanDefinition, "BeanDefinition must not be null"); 12 13 if (beanDefinition instanceof AbstractBeanDefinition) { 14 try { 15 ((AbstractBeanDefinition) beanDefinition).validate(); 16 } 17 catch (BeanDefinitionValidationException ex) { 18 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, 19 "Validation of bean definition failed", ex); 20 } 21 } 22 23 synchronized (this.beanDefinitionMap) { 24 Object oldBeanDefinition = this.beanDefinitionMap.get(beanName); 25 if (oldBeanDefinition != null) { 26 if (!this.allowBeanDefinitionOverriding) { 27 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, 28 "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + 29 "': There is already [" + oldBeanDefinition + "] bound."); 30 } 31 else { 32 if (this.logger.isInfoEnabled()) { 33 this.logger.info("Overriding bean definition for bean '" + beanName + 34 "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); 35 } 36 } 37 } 38 else { 39 this.beanDefinitionNames.add(beanName); 40 this.frozenBeanDefinitionNames = null; 41 } 42 this.beanDefinitionMap.put(beanName, beanDefinition); 43 } 44 45 resetBeanDefinition(beanName); 46 }
二、 Spring-MVC中Controller中的method與 RequestMappingURL的初始化
1. Controller中的method與 RequestMappingURL的映射關系綁定初始化工作主要在spring-webmvc.jar中完成。這個jar 文件包含Spring MVC 框架相關的所有類,
包括框架的Servlets,Web MVC框架,控制器和視圖支持。
2. SpringMVC在容器初始化時,綁定請求URL映射到相應的Controller中的方法的工作主要在org.springframework.web.servlet.handler.AbstractHandlerMethodMapping類中的initHandlerMethods方法完成,
AbstractHandlerMethodMapping實現了Spring的org.springframework.beans.factory.InitializingBean接口,在InitializingBean的afterPropertiesSet即調用了initHandlerMethods。
MappingURL與Controller對應方法的映射關系在servlet容器初始化時保存到 AbstractHandlerMethodMapping中的成員變量urlMap中。
AbstractHandlerMethodMapping類的initHandlerMethods為protected修飾 ,可被子類重寫。
三、 請求URL到達映射處理的Controller的Method前的邏輯。
執行業務方法的邏輯主要在org.springframework.web.servlet.DispatcherServlet類的doDispatch方法中。
以下為doDispatch方法的代碼:
/** * 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); } } }
主要執行的過程有四個步驟,如下所示:
1. 通過調用org.springframework.web.servlet.handler.AbstractHandlerMethodMapping類的getHandlerInternal方法來獲得相應的請求url的映射的controller和method的HandlerMethod,
AbstractHandlerMethodMapping中的成員變量urlMap保存的即為servlet容器啟動時初始化的RequestMapping映射的Controller和Method的信息。
getHandlerInternal方法代碼如下:
/** * Look up the best-matching handler method for the current request. * If multiple matches are found, the best match is selected. * @param lookupPath mapping lookup path within the current servlet mapping * @param request the current request * @return the best-matching handler method, or {@code null} if no match * @see #handleMatch(Object, String, HttpServletRequest) * @see #handleNoMatch(Set, String, HttpServletRequest) */ protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { List<Match> matches = new ArrayList<Match>(); List<T> directPathMatches = this.urlMap.get(lookupPath); if (directPathMatches != null) { addMatchingMappings(directPathMatches, matches, request); } if (matches.isEmpty()) { // No choice but to go through all mappings addMatchingMappings(this.handlerMethods.keySet(), matches, request); } if (!matches.isEmpty()) { Comparator<Match> comparator = new MatchComparator(getMappingComparator(request)); Collections.sort(matches, comparator); if (logger.isTraceEnabled()) { logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches); } Match bestMatch = matches.get(0); if (matches.size() > 1) { Match secondBestMatch = matches.get(1); if (comparator.compare(bestMatch, secondBestMatch) == 0) { Method m1 = bestMatch.handlerMethod.getMethod(); Method m2 = secondBestMatch.handlerMethod.getMethod(); throw new IllegalStateException( "Ambiguous handler methods mapped for HTTP path '" + request.getRequestURL() + "': {" + m1 + ", " + m2 + "}"); } } handleMatch(bestMatch.mapping, lookupPath, request); return bestMatch.handlerMethod; } else { return handleNoMatch(handlerMethods.keySet(), lookupPath, request); } }
HandlerMethod類主要包括的信息有 匹配處理的Controller ,處理方法Method,以及方法的傳入參數 parameters等信息。HandlerMethod的主要成員變量代碼如下:
public class HandlerMethod { /** Logger that is available to subclasses */ protected final Log logger = LogFactory.getLog(HandlerMethod.class); private final Object bean; private final Method method; private final BeanFactory beanFactory; private MethodParameter[] parameters; private final Method bridgedMethod; }
2. 執行url匹配的過濾器的preHandle方法。
3. 執行主要的業務過程處理方法,即執行步驟1中找到的Controller對應的Method。
執行主要的業務處理方法的是在org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter類的invokeHandlerMethod方法中調用。
/** * Invoke the {@link RequestMapping} handler method preparing a {@link ModelAndView} if view resolution is required. */ private ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest(request, response); WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory); ModelAndViewContainer mavContainer = new ModelAndViewContainer(); mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); modelFactory.initModel(webRequest, mavContainer, requestMappingMethod); mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect); requestMappingMethod.invokeAndHandle(webRequest, mavContainer); modelFactory.updateModel(webRequest, mavContainer); if (mavContainer.isRequestHandled()) { return null; } else { ModelMap model = mavContainer.getModel(); ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model); if (!mavContainer.isViewReference()) { mav.setView((View) mavContainer.getView()); } if (model instanceof RedirectAttributes) { Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes(); RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes); } return mav; } }
業務方法調用主要在org.springframework.web.method.support.InvocableHandlerMethod類的invokeForRequest方法中,過程包括組裝request的請求參數傳入到handleMethod的參數數組args[]中,方法調用等。
/** * Invoke the method after resolving its argument values in the context of the given request. <p>Argument * values are commonly resolved through {@link HandlerMethodArgumentResolver}s. The {@code provideArgs} * parameter however may supply argument values to be used directly, i.e. without argument resolution. * Examples of provided argument values include a {@link WebDataBinder}, a {@link SessionStatus}, or * a thrown exception instance. Provided argument values are checked before argument resolvers. * * @param request the current request * @param mavContainer the ModelAndViewContainer for this request * @param providedArgs "given" arguments matched by type, not resolved * @return the raw value returned by the invoked method * @exception Exception raised if no suitable argument resolver can be found, or the method raised an exception */ public final Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); if (logger.isTraceEnabled()) { StringBuilder builder = new StringBuilder("Invoking ["); builder.append(this.getMethod().getName()).append("] method with arguments "); builder.append(Arrays.asList(args)); logger.trace(builder.toString()); } Object returnValue = invoke(args); if (logger.isTraceEnabled()) { logger.trace("Method [" + this.getMethod().getName() + "] returned [" + returnValue + "]"); } return returnValue; }
4. 執行url匹配的過濾器的postHandle方法。