一、 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方法。