Spring MVCのDispatcherServiceリクエスト処理
15416 ワード
処理要求はMVCのC(Control)部分であり、MVCの核心内容である.初期化コンテキストでは、すべてのHandlerMappingをhandlerMappingsにロードし、Orderに従ってソートします.各HandlerMappingは、ControllerへのURLのマッピング関係を持つ.
MVC初期化完了後、Http要求の処理はdoService()メソッドで行われる.DispatcherServiceletはHttptServiceletのサブクラスであり、Httpリクエストの処理はdoService()メソッドで行われる.
初期化が完了すると、コンテキストで構成されたすべてのHandlerMappingがロードされた(HandlerMap初期化)、並べ替えられて1つのリストに格納される.HandlerMappingは、Http要求と対応するプロセッサのマッピングデータとを格納する.
要求の実際の処理はdoDispatche()メソッドで行われ、主なステップは次のとおりです.
ModelAndView, の準備 getHandlerを呼び出して、要求を処理するHandlerを取得し、 .そしてhandler応答要求によりModelAndViewオブジェクトを返す 最後に、このModelAndViewをビューオブジェクトに渡して表示します.
doServiceはHttpService Request要求を受信し、要求パラメータの初期化後にdoDispatch()に直接要求を委任します.線面はdoServiceソースです.
doDispatch()は、HttpServertRequestリクエストが真に処理されるクラスであり、
このクラスではまずHandlerMappingsから順にマッチングの有無をチェックする処理方法である.HandlerMappings内のすべてのhandlerMapが一致する処理方法がない場合は、404を返す.次はdoDispatchソースコードの分析です.
getHandlerはhandlerMappingsを遍歴するプロセスであり、そのうちの1つのhandlerMappingsに一致する処理方法があればそのHandlerExecutionChainに戻る.
HandlerExeutionChainにはHnadlerオブジェクトといくつかの列のブロッキングが含まれています
HandlerMappingで現在の要求の処理Handleが見つかった後、HandlerAdapterはこのプロセッサ処理要求を呼び出します.
MVC初期化完了後、Http要求の処理はdoService()メソッドで行われる.DispatcherServiceletはHttptServiceletのサブクラスであり、Httpリクエストの処理はdoService()メソッドで行われる.
初期化が完了すると、コンテキストで構成されたすべてのHandlerMappingがロードされた(HandlerMap初期化)、並べ替えられて1つのリストに格納される.HandlerMappingは、Http要求と対応するプロセッサのマッピングデータとを格納する.
/**
* Http handler * , , BeanNameUrlHanlderMapping SimpleUrlHandlerMapping。 * HandlerMapping HandlerMapping HandlerMapping
* *HandlerMapping , 。 Handler HandlerExutionChain , * 。DispatcherServlet preHandler , preHandler true, ** handler 。
**/
public interface HandlerMapping {
String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";
String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern";
String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping.class.getName() + ".introspectTypeLevelMapping";
String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables";
String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping.class.getName() + ".producibleMediaTypes";
/**
。 URL, 。
HandlerExecutionChain , ,
null, 。
DispatcherServlet HanlderMapping Handler,
*/
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
要求の実際の処理はdoDispatche()メソッドで行われ、主なステップは次のとおりです.
doServiceはHttpService Request要求を受信し、要求パラメータの初期化後にdoDispatch()に直接要求を委任します.線面はdoServiceソースです.
/**
* Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}
* for the actual dispatching.
*/
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
String requestUri = urlPathHelper.getRequestUri(request);
logger.debug("DispatcherServlet with name '" + getServletName() + "' processing " + request.getMethod() +
" request for [" + requestUri + "]");
}
// Keep a snapshot of the request attributes in case of an include,
// to be able to restore the original attributes after the include.
Map<String, Object> attributesSnapshot = null;
//
if (WebUtils.isIncludeRequest(request)) {
logger.debug("Taking snapshot of request attributes before include");
attributesSnapshot = new HashMap<String, Object>();
//
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// Make framework objects available to handlers and view objects.
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
try {
doDispatch(request, response);
}
finally {
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
doDispatch()は、HttpServertRequestリクエストが真に処理されるクラスであり、
このクラスではまずHandlerMappingsから順にマッチングの有無をチェックする処理方法である.HandlerMappings内のすべてのhandlerMapが一致する処理方法がない場合は、404を返す.次は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);
// HandlerExecutionChain
mappedHandler = getHandler(processedRequest, false);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
// , 404
noHandlerFound(processedRequest, response);
return;
}
// Handler
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
//
String method = request.getMethod();
// GET
boolean isGet = "GET".equals(method);
// GET HEAD
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;
}
}
//
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;
}
}
//
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// , view,
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);
}
//
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);
}
}
}
getHandlerはhandlerMappingsを遍歴するプロセスであり、そのうちの1つのhandlerMappingsに一致する処理方法があればそのHandlerExecutionChainに戻る.
/**
* Return the HandlerExecutionChain for this request.
* <p>Tries all handler mappings in order.
* @param request current HTTP request
* @return the HandlerExecutionChain, or <code>null</code> if no handler could be found
*/
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
/**
* ,
* @param request current HTTP request
* @return the corresponding handler instance, or the default handler
* @see #getHandlerInternal
*/
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
//
if (handler == null) {
handler = getDefaultHandler();
}
// null
if (handler == null) {
return null;
}
// Bean
if (handler instanceof String) {
String handlerName = (String) handler;
//
handler = getApplicationContext().getBean(handlerName);
}
return getHandlerExecutionChain(handler, request);
}
HandlerExeutionChainにはHnadlerオブジェクトといくつかの列のブロッキングが含まれています
/**
* Handler execution chain, consisting of handler object and any handler interceptors.
* Returned by HandlerMapping's {@link HandlerMapping#getHandler} method.
*
* @author Juergen Hoeller
* @since 20.06.2003
* @see HandlerInterceptor
*/
public class HandlerExecutionChain {
private final Object handler;
private HandlerInterceptor[] interceptors;
private List<HandlerInterceptor> interceptorList;
HandlerMappingで現在の要求の処理Handleが見つかった後、HandlerAdapterはこのプロセッサ処理要求を呼び出します.
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//
Class<?> clazz = ClassUtils.getUserClass(handler);
// ,
Boolean annotatedWithSessionAttributes = this.sessionAnnotatedClassesCache.get(clazz);
// , controller @SessionAttribute ,
if (annotatedWithSessionAttributes == null) {
annotatedWithSessionAttributes = (AnnotationUtils.findAnnotation(clazz, SessionAttributes.class) != null);
this.sessionAnnotatedClassesCache.put(clazz, annotatedWithSessionAttributes);
}
if (annotatedWithSessionAttributes) {
checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
}
else {
checkAndPrepare(request, response, true);
}
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
return invokeHandlerMethod(request, response, handler);
}
}
}
return invokeHandlerMethod(request, response, handler);
}
//
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);
//
Method handlerMethod = methodResolver.resolveHandlerMethod(request);
ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);
ServletWebRequest webRequest = new ServletWebRequest(request, response);
ExtendedModelMap implicitModel = new BindingAwareModelMap();
//
Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
ModelAndView mav =
methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);
methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);
return mav;
}