SpringMVCソース解析

129946 ワード

記事の目次
  • SpringMVCソース解析
  • 一、大まかな流れ
  • 、doDisplatchソース表示版:
  • 、詳細
  • 、get Handler()詳細
  • 、get Handler Adapter()詳細
  • 、SpringMVCの九大コンポーネント
  • 、onRefresh()初期化詳細
  • 、handle()の詳細
  • (1)invokeHandlerMethod方法
  • (2)reolveHandlerAgments決定パラメータ
  • (3)reolveCommargment解析一般パラメータ
  • (4)reolveStandardAgment解析標準パラメータ
  • (5)カスタムパラメータ決定値
  • (6)パラメータ決定総括(難点)
  • SpringMVCソース解析
    一、大体の流れ
    1)、すべての要求をDisplatch Servletに来て処理する。
    2)、doDisplatch()を呼び出して処理する。
    1、getHandler():現在の要求に基づいて、HandlerMappingにこの要求のマッピング情報を見つけて、この要求を処理できる対象プロセッサ類を見つけます。
    2、getHandlerAdfapter():このプロセッサ方法を実行できるアダプターを現在のプロセッサ類から取得します。
    3、先ほどのアダプターを使って目標方法を実行します。
    4、目標方法を実行したらModelAndViewオブジェクトに戻ります。
    5、ModelAndViewの情報に基づいて具体的なページに転送し、ModelMapのデータを要求ドメインから取り出すことができます。
    二、doDisplatchソース表示版:
    doDispatch()protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;
    
        //             ,       ,    
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    
        try {
            ModelAndView mv = null;
            Exception dispatchException = null;
    
            try {
                //(1)          (   ,     )
                //               ,     request     processedRequest
                processedRequest = checkMultipart(request);
                //   processedRequest request           ,     multipartRequestParsed(Boolean) 
                multipartRequestParsed = processedRequest != request;
    
                //(2)             
                // Determine handler for the current request.
                //      handler(Controller)        ,           ,            
                // *  :*
                // 1.              (  ),     default-servlet-handler,     mappedHandler    null
                // 2. mappedHandler   HandlerExecutionChain     ,  handler(        )、interceptorList(     ) 
                mappedHandler = getHandler(processedRequest);
    
                //(3)      ,  404,   
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    //           ,     ,       
                    noHandlerFound(processedRequest, response);
                    return;
                }
    
                // Determine handler adapter for the current request.
                // (4)                (    )
                // *  :*
                //       annotation-driven,  Handler AnnotationMethodHandlerAdpater   
                //          Handler  RequestMappingHandlerAdpater   
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    
                // Process last-modified header, if supported by the handler.
                //        (Get、Post...),       ,lastModified  (      ,  )
                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;
                    }
                }
    
                //     preHandle  
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }
    
                try {
                    //      (handlerAdpater)  handler(Controller)     
                    // (5)         ,    ModelAndView   
                    //          ,              ModelAndView  
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                }
                finally {
                    //               ,   ,        
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }
                }
    
                //        ,         ,    
                applyDefaultViewName(request, mv);
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
            catch (Exception ex) {
                dispatchException = ex;
            }
            //        ,      ,       
            // (6)  ModelAndView,       
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Error err) {
            triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
        }
        finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                // Instead of postHandle and afterCompletion
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                return;
            }
            // Clean up any resources used by a multipart request.
            if (multipartRequestParsed) {
                cleanupMultipart(processedRequest);
            }
        }
    }
    
    ----------------------------------------------------------
    三、細かいところ
    1、get Handler()詳細
    どのように現在の要求に基づいてどの種類のエネルギーを見つけて処理しますか?
    -HandlerExecution Charinタイプのオブジェクトを返します。handleer(目標処理方法情報)、interceptorList(ブロッキング情報)などが含まれます。
    get Handler():
    handleMappings:プロセッサマッピングは、各プロセッサがどのような要求を処理できますか?
  • ビーンNameUrlhandlerMappingは、プロファイル
  • を介して構成されている。
  • Default AnnotationhandlerMappingは注釈を通して、注釈で表示されたRequest Mappingマッピング関係は全部この種類のhandle Mapの中にあります。
    なぜハンドルMappingsはマッピングを保存しましたか?
    IOC起動時はすべてのControllerをスキャンし、Request MappingをDefault AnnotationHandlerMappingに保存します。
    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;
    }
    
    2、get Handler Adapter()詳細
    どのように現在の要求に基づいてどの種類のエネルギーを見つけて処理しますか?
    HandlerAdapterはプロセッサ方法を呼び出し、プロセッサ方法にパラメータ解析、戻り値処理などの適応作業を提供し、ユーザーを業務ロジックの実現に専念させる。
    get Handler Adapter():
    すべてのhanderAdaptersを巡回して、どのadaterがsupportこのhandlerを見ることができますか?(handle Adaptersはデフォルトで3つのhanderAdapterがあります。)
  • HttpRequest HandlerAdapterは、HttpRequest Handlerインターフェースを実現し、Http requestsを処理するために使用され、簡単なServlet
  • と類似しています。
  • SimpleController HandlerAdapterがControllerインターフェースを実現するプロセッサ、
  • あなたのカスタムコントローラがもし実装されているのがControllerインターフェースであれば、SimpleController Handler Adapterアダプタを使用してカスタムControllerを実行する必要があります。
  • AnnotationMethodhandler Adapterが注釈方法を解析できるアダプター(annotationn-drivenが配置されていないのはこれです。)
  • protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        Iterator var2 = this.handlerAdapters.iterator();
    
        HandlerAdapter ha;
        do {
            if (!var2.hasNext()) {
                throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
            }
    
            ha = (HandlerAdapter)var2.next();
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Testing handler adapter [" + ha + "]");
            }
        } while(!ha.supports(handler));
    
        return ha;
    }
    
    3、SprigMVCの九大セット
    Displatch Srvletにはいくつかの引用タイプの属性があります。SpringMVCの九大コンポーネントです。
    SpringMVCは仕事をする時、肝心な位置はすべてこれらの部品から完成したのです。共通点:九大の部品は全部「インターフェース」で、インターフェースは拡張性を提供しました。
    SpringMVCの九大コンポーネントの作業原理(オーディエンスレベル)
    /** MultipartResolver used by this servlet */
    /**         */
    private MultipartResolver multipartResolver;//      
    
    /** LocaleResolver used by this servlet */
    /**        ,       */
    private LocaleResolver localeResolver;
    
    /** ThemeResolver used by this servlet */
    /**      ,         */
    private ThemeResolver themeResolver;
    
    /** List of HandlerMappings used by this servlet */
    /** Handler     */
    private List<HandlerMapping> handlerMappings;
    
    /** List of HandlerAdapters used by this servlet */
    /** Handler     */
    private List<HandlerAdapter> handlerAdapters;
    
    /** List of HandlerExceptionResolvers used by this servlet */
    /** SpringMVC          */
    private List<HandlerExceptionResolver> handlerExceptionResolvers;
    
    /** RequestToViewNameTranslator used by this servlet */
    /**     ,     */
    private RequestToViewNameTranslator viewNameTranslator;
    
    /** FlashMapManager used by this servlet */
    /** SpringMVC              */
    private FlashMapManager flashMapManager;
    
    /** List of ViewResolvers used by this servlet */
    /**       */
    private List<ViewResolver> viewResolvers;
    
    4、onRefsh()初期化の詳細
  • Displatch Servletは、SpringIOC容器refresh()におけるサブクラスの実現のための一歩にちょうど対応する方法を実現しました。
  • したがって、このonRefresh()方法は、IOC容器を初期化する際に実行され、9つのコンポーネントを初期化するために使用される。
    @Override
    protected void onRefresh(ApplicationContext context) {
        initStrategies(context);
    }
    
    コンポーネントの初期化:
    いくつかのコンポーネントはコンテナの中でタイプを使って探しています。一部のコンポーネントはIDを使って探しています。
    容器の中にこの部品を探しに行きます。見つけられなかったら、デフォルトの設定を使います。
    /**
        * Initialize the strategy objects that this servlet uses.
        * 

    May be overridden in subclasses in order to initialize further strategy objects. */

    protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); }
    例えば、初期化HanderMappings:DispatcherServlet.propertiesの九つのコンポーネントのデフォルトクラスをロードします。
    例えば、HadleMappingはBeanNameUrlHandlerMappingDefaultAnnotationHandlerMappingです。
    private void initHandlerMappings(ApplicationContext context) {
        this.handlerMappings = null;
    
        //    web.xml    DispatcherServlet     ,  detectAllHandlerMappings
    
        //  IOC       HandlerMapping   
        if (this.detectAllHandlerMappings) {
            // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
            Map<String, HandlerMapping> matchingBeans =
                    BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
                // We keep HandlerMappings in sorted order.
                OrderComparator.sort(this.handlerMappings);
            }
        }
        else {
            //       ,      ID “handlerMapping”   
            try {
                HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
                this.handlerMappings = Collections.singletonList(hm);
            }
            catch (NoSuchBeanDefinitionException ex) {
                // Ignore, we'll add a default HandlerMapping later.
            }
        }
    
        // Ensure we have at least one HandlerMapping, by registering
        // a default HandlerMapping if no other mappings are found.
        //       ,      handlerMapping 
        // !!!   DispatcherServlet.properties         !!!
        // 
        if (this.handlerMappings == null) {
            this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
            if (logger.isDebugEnabled()) {
                logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
            }
        }
    }
    
    5、ハンドルの詳細
  • ダミーモデルimplicitModelにおけるデータは、Requestドメインで
  • に取り込まれてもよい。
    ターゲット方法の実行にロックします。handle()の詳細(反射はパラメータなどをどうやって決定しますか?)
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    
  • invokeHandlerMethod)Session Atributesのオブジェクトに値があれば、暗黙のモデルimplicitModel
  • に追加する。
  • (invokeHandlerMethod)すべてのModelAttributeの表示を行う方法
  • invokeHandlerMethod)は、目標方法
  • を実行する。
    ModelAttributeの方法と目標方法を実行する時、方法のパラメータを決めます。デザインは巧みです。
  • resolveHandlerArgumentsは、パラメータを決定し、先に注釈表示のパラメータかどうかを見て、解析を行い、そうでない場合は、resolveCommonArgumentを呼び出して、通常パラメータ
  • を解析する。
  • resolveCommonArgumentは、まず、resoveStandardAgment解析標準パラメータ(Requestなどの元のコンポーネントを充填する)を呼び出し、その後、コンポーネントがModelまたはMapタイプであるかどうかを見て、直接implicitModel
  • に伝えます。
  • resolveStandardArgument解析標準パラメータ(ここにRequestなどの元の部品を充填する)
  • ModelAttributeメソッドにvalue識別子がないと表示されていると、返ってきた値の種類をatrNameとして解析し、戻り値を暗黙のモデルimplicitModelに追加します。
    @Override
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        //   handler      (@Controller       )
        Class<?> clazz = ClassUtils.getUserClass(handler);
        //            SessionAttribute  
        Boolean annotatedWithSessionAttributes = this.sessionAnnotatedClassesCache.get(clazz);
        if (annotatedWithSessionAttributes == null) {
            annotatedWithSessionAttributes = (AnnotationUtils.findAnnotation(clazz, SessionAttributes.class) != null);
            this.sessionAnnotatedClassesCache.put(clazz, annotatedWithSessionAttributes);
        }
    
        if (annotatedWithSessionAttributes) {
            // Always prevent caching in case of session attribute management.
            checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
            // Prepare cached set of session attributes names.
        }
        else {
            // Uses configured default cacheSeconds setting.
            //     ,    ,     
            checkAndPrepare(request, response, true);
        }
    
        // Execute invokeHandlerMethod in synchronized block if required.
        if (this.synchronizeOnSession) {
            HttpSession session = request.getSession(false);
            if (session != null) {
                Object mutex = WebUtils.getSessionMutex(session);
                synchronized (mutex) {
                    return invokeHandlerMethod(request, response, handler);
                }
            }
        }
        //     ,   invokeHandlerMethod  
        return invokeHandlerMethod(request, response, handler);
    }
    
    
    protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        //          
        ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);
        //   request            
        Method handlerMethod = methodResolver.resolveHandlerMethod(request);
        //         
        ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);
        // request、response    
        ServletWebRequest webRequest = new ServletWebRequest(request, response);
        //   implicitModel    (   BindingAwareModelMap  ,   Map            )    implicit:   、  
        ExtendedModelMap implicitModel = new BindingAwareModelMap();
    
    
        /**
        *           ,       ,        ,  (success)(             ,    modelAttribute          )
        */
        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;
    }
    
    (1)invokeHandler Method方法
    このクラスの重要なロジックの一部
    public final Object invokeHandlerMethod(Method handlerMethod, Object handler,
    			NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception {
    
        Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod);
        try {
            boolean debug = logger.isDebugEnabled();
            //  SessionAtributes       ,       
            for (String attrName : this.methodResolver.getActualSessionAttributeNames()) {
                Object attrValue = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName);
                if (attrValue != null) {
                    implicitModel.addAttribute(attrName, attrValue);
                }
            }
            // ***************  *****************
            //      ModelAttribute     ,           
            for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) {
                Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod);
                // ***************  *****************
                //   ModelAttribute                
                Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel);
              
                if (debug) {
                    logger.debug("Invoking model attribute method: " + attributeMethodToInvoke);
                }
                String attrName = AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value();
                if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) {
                    continue;
                }
                ReflectionUtils.makeAccessible(attributeMethodToInvoke);
                // ***************  *****************
                //       
                Object attrValue = attributeMethodToInvoke.invoke(handler, args);
              
              
                if ("".equals(attrName)) {
                    Class<?> resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass());
                    attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue);
                }
                if (!implicitModel.containsAttribute(attrName)) {
                    implicitModel.addAttribute(attrName, attrValue);
                }
            }
            //          !!! ModelAttribute  
            Object[] args = resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel);
            if (debug) {
                logger.debug("Invoking request handler method: " + handlerMethodToInvoke);
            }
            ReflectionUtils.makeAccessible(handlerMethodToInvoke);
            //       !!
            return handlerMethodToInvoke.invoke(handler, args);
        }
        catch (IllegalStateException ex) {
            // Internal assertion failed (e.g. invalid signature):
            // throw exception with full handler method context...
            throw new HandlerMethodInvocationException(handlerMethodToInvoke, ex);
        }
        catch (InvocationTargetException ex) {
            // User-defined @ModelAttribute/@InitBinder/@RequestMapping method threw an exception...
            ReflectionUtils.rethrowException(ex.getTargetException());
            return null;
        }
    }
    
    (2)reolveHandlerAgments決定パラメータ
    ModelAttribute表示の方法は、事前に実行され、実行後の戻り値を暗黙のモデルに追加する(方法実行の詳細)resolveHandlerArguments
    private Object[] resolveHandlerArguments(Method handlerMethod, Object handler,
    			NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception {
    
        Class<?>[] paramTypes = handlerMethod.getParameterTypes();
        Object[] args = new Object[paramTypes.length];
    
      	//            
        for (int i = 0; i < args.length; i++) {
            MethodParameter methodParam = new MethodParameter(handlerMethod, i);
            methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer);
            GenericTypeResolver.resolveParameterType(methodParam, handler.getClass());
            String paramName = null;
            String headerName = null;
            boolean requestBodyFound = false;
            String cookieName = null;
            String pathVarName = null;
            String attrName = null;
            boolean required = false;
            String defaultValue = null;
            boolean validate = false;
            Object[] validationHints = null;
            int annotationsFound = 0;
            //           
            Annotation[] paramAnns = methodParam.getParameterAnnotations();
    				//              ,    ,    
            for (Annotation paramAnn : paramAnns) {
                //    RequestParam
                if (RequestParam.class.isInstance(paramAnn)) {
                    RequestParam requestParam = (RequestParam) paramAnn;
                    //    
                    paramName = requestParam.value();
                    //   required  
                    required = requestParam.required();
                    defaultValue = parseDefaultValueAttribute(requestParam.defaultValue());
                    //       ,   ++
                    annotationsFound++;
                }
                //    RequestHeader
                else if (RequestHeader.class.isInstance(paramAnn)) {
                    RequestHeader requestHeader = (RequestHeader) paramAnn;
                    headerName = requestHeader.value();
                    required = requestHeader.required();
                    defaultValue = parseDefaultValueAttribute(requestHeader.defaultValue());
                    annotationsFound++;
                }
                //    RequestBody
                else if (RequestBody.class.isInstance(paramAnn)) {
                    requestBodyFound = true;
                    annotationsFound++;
                }
                //    CookieValue
                else if (CookieValue.class.isInstance(paramAnn)) {
                    CookieValue cookieValue = (CookieValue) paramAnn;
                    cookieName = cookieValue.value();
                    required = cookieValue.required();
                    defaultValue = parseDefaultValueAttribute(cookieValue.defaultValue());
                    annotationsFound++;
                }
                //    PathVariable
                else if (PathVariable.class.isInstance(paramAnn)) {
                    PathVariable pathVar = (PathVariable) paramAnn;
                    pathVarName = pathVar.value();
                    annotationsFound++;
                }
                //    ModelAttribute
                else if (ModelAttribute.class.isInstance(paramAnn)) {
                    ModelAttribute attr = (ModelAttribute) paramAnn;
                    attrName = attr.value();
                    annotationsFound++;
                }
                //    Value
                else if (Value.class.isInstance(paramAnn)) {
                    defaultValue = ((Value) paramAnn).value();
                }
                //    。。。
                else if (paramAnn.annotationType().getSimpleName().startsWith("Valid")) {
                    validate = true;
                    Object value = AnnotationUtils.getValue(paramAnn);
                    validationHints = (value instanceof Object[] ? (Object[]) value : new Object[] {value});
                }
            }
    				//           ,   
            if (annotationsFound > 1) {
                throw new IllegalStateException("Handler parameter annotations are exclusive choices - " +
                        "do not specify more than one such annotation on the same parameter: " + handlerMethod);
            }
            //         
            if (annotationsFound == 0) {
                //       
                Object argValue = resolveCommonArgument(methodParam, webRequest);
                //         (    )  ,    
                if (argValue != WebArgumentResolver.UNRESOLVED) {
                    args[i] = argValue;
                }
              	//       
                else if (defaultValue != null) {
                    args[i] = resolveDefaultValue(defaultValue);
                }
                else {
                  	//       
                    Class<?> paramType = methodParam.getParameterType();
                  	// ************  *************
                  	//   Model   !!  Map  
                    //    implicitModel   
                  	// *****************************
                    if (Model.class.isAssignableFrom(paramType) || Map.class.isAssignableFrom(paramType)) {
                        if (!paramType.isAssignableFrom(implicitModel.getClass())) {
                            throw new IllegalStateException("Argument [" + paramType.getSimpleName() + "] is of type " +
                                    "Model or Map but is not assignable from the actual model. You may need to switch " +
                                    "newer MVC infrastructure classes to use this argument.");
                        }
                        args[i] = implicitModel;
                    }
                  	//   SessionStatus  
                    else if (SessionStatus.class.isAssignableFrom(paramType)) {
                        args[i] = this.sessionStatus;
                    }
                  	//   HttpEntity  
                    else if (HttpEntity.class.isAssignableFrom(paramType)) {
                        args[i] = resolveHttpEntityRequest(methodParam, webRequest);
                    }
                  	//   Errors  
                    else if (Errors.class.isAssignableFrom(paramType)) {
                        throw new IllegalStateException("Errors/BindingResult argument declared " +
                                "without preceding model attribute. Check your handler method signature!");
                    }
                    else if (BeanUtils.isSimpleProperty(paramType)) {
                        paramName = "";
                    }
                    else {
                        attrName = "";
                    }
                }
            }
    
            if (paramName != null) {
                args[i] = resolveRequestParam(paramName, required, defaultValue, methodParam, webRequest, handler);
            }
            else if (headerName != null) {
                args[i] = resolveRequestHeader(headerName, required, defaultValue, methodParam, webRequest, handler);
            }
            else if (requestBodyFound) {
                args[i] = resolveRequestBody(methodParam, webRequest, handler);
            }
            else if (cookieName != null) {
                args[i] = resolveCookieValue(cookieName, required, defaultValue, methodParam, webRequest, handler);
            }
            else if (pathVarName != null) {
                args[i] = resolvePathVariable(pathVarName, methodParam, webRequest, handler);
            }
            else if (attrName != null) {
                WebDataBinder binder =
                        resolveModelAttribute(attrName, methodParam, implicitModel, webRequest, handler);
                boolean assignBindingResult = (args.length > i + 1 && Errors.class.isAssignableFrom(paramTypes[i + 1]));
                if (binder.getTarget() != null) {
                    doBind(binder, webRequest, validate, validationHints, !assignBindingResult);
                }
                args[i] = binder.getTarget();
                if (assignBindingResult) {
                    args[i + 1] = binder.getBindingResult();
                    i++;
                }
                implicitModel.putAll(binder.getBindingResult().getModel());
            }
        }
    
        return args;
    }
    
    (3)resoveCommon Agment解析一般パラメータ
    protected Object resolveCommonArgument(MethodParameter methodParameter, NativeWebRequest webRequest)
    			throws Exception {
    	
    		// Invoke custom argument resolvers if present...
      	//           ,   
    		if (this.customArgumentResolvers != null) {
    			for (WebArgumentResolver argumentResolver : this.customArgumentResolvers) {
    				Object value = argumentResolver.resolveArgument(methodParameter, webRequest);
    				if (value != WebArgumentResolver.UNRESOLVED) {
    					return value;
    				}
    			}
    		}
    
    		// Resolution of standard parameter types...
    		Class<?> paramType = methodParameter.getParameterType();
        //         
    		Object value = resolveStandardArgument(paramType, webRequest);
    		if (value != WebArgumentResolver.UNRESOLVED && !ClassUtils.isAssignableValue(paramType, value)) {
    			throw new IllegalStateException("Standard argument type [" + paramType.getName() +
    					"] resolved to incompatible value of type [" + (value != null ? value.getClass() : null) +
    					"]. Consider declaring the argument type in a less specific fashion.");
    		}
    		return value;
    	}
    
    (4)resoveStandardAgment解析基準パラメータ
    この方法はAnnotationMethodHandlerMappingにある。
    @Override
    		protected Object resolveStandardArgument(Class<?> parameterType, NativeWebRequest webRequest) throws Exception {
    			HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
    			HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
          //                 API   
    			//          ServletRequest
    			if (ServletRequest.class.isAssignableFrom(parameterType) ||
    					MultipartRequest.class.isAssignableFrom(parameterType)) {
    				Object nativeRequest = webRequest.getNativeRequest(parameterType);
    				if (nativeRequest == null) {
    					throw new IllegalStateException(
    							"Current request is not of type [" + parameterType.getName() + "]: " + request);
    				}
    				return nativeRequest;
    			}
          //          ServletResponse
    			else if (ServletResponse.class.isAssignableFrom(parameterType)) {
    				this.responseArgumentUsed = true;
    				Object nativeResponse = webRequest.getNativeResponse(parameterType);
    				if (nativeResponse == null) {
    					throw new IllegalStateException(
    							"Current response is not of type [" + parameterType.getName() + "]: " + response);
    				}
    				return nativeResponse;
    			}
          //          HttpSession
    			else if (HttpSession.class.isAssignableFrom(parameterType)) {
    				return request.getSession();
    			}
          //          Principal
    			else if (Principal.class.isAssignableFrom(parameterType)) {
    				return request.getUserPrincipal();
    			}
          //          Locale
    			else if (Locale.class.equals(parameterType)) {
    				return RequestContextUtils.getLocale(request);
    			}
          //          InputStream
    			else if (InputStream.class.isAssignableFrom(parameterType)) {
    				return request.getInputStream();
    			}
          //          Reader
    			else if (Reader.class.isAssignableFrom(parameterType)) {
    				return request.getReader();
    			}
          //          OutputStream
    			else if (OutputStream.class.isAssignableFrom(parameterType)) {
    				this.responseArgumentUsed = true;
    				return response.getOutputStream();
    			}
          //          Writer
    			else if (Writer.class.isAssignableFrom(parameterType)) {
    				this.responseArgumentUsed = true;
    				return response.getWriter();
    			}
    			return super.resolveStandardArgument(parameterType, webRequest);
    		}
    
    (5)カスタムパラメータ決定値
  • は、まず、元のAPIとの関連があるかどうかを見て、resoveStandardAgment方法で
  • を処理する。
  • ModelまたはMapタイプのパラメータが、暗黙的なモデルに入ってきたかどうかを見て、他のタイプのパラメータ、例えばSession Stuts、HttpEntity、resoveHandlerAgments方法で
  • を処理します。
  • は、単純なタイプかどうか(Integer、String...)を見ています。もし、パラムName=「」であれば、BeanUtils.isSimpleProperty(paramType)は、reolveHandlerAgments方法で
  • です。
  • もし全部ではないなら、atrName=""(例えばPOJO、Book、Personタイプ)は、reolveHandlerAgments方法で
  • です。
    カスタムパラメータを解析します。
    else if (attrName != null) {
    				WebDataBinder binder =
    						resolveModelAttribute(attrName, methodParam, implicitModel, webRequest, handler);
    				boolean assignBindingResult = (args.length > i + 1 && Errors.class.isAssignableFrom(paramTypes[i + 1]));
    				if (binder.getTarget() != null) {
              //               
    					doBind(binder, webRequest, validate, validationHints, !assignBindingResult);
    				}
    				args[i] = binder.getTarget();
    				if (assignBindingResult) {
    					args[i + 1] = binder.getBindingResult();
    					i++;
    				}
    				implicitModel.putAll(binder.getBindingResult().getModel());
    			}
    
    resolveModelAttribute方法
    private WebDataBinder resolveModelAttribute(String attrName, MethodParameter methodParam,
    			ExtendedModelMap implicitModel, NativeWebRequest webRequest, Object handler) throws Exception {
    
    		// Bind request parameter onto object...
    		String name = attrName;
        //   attrName  ,      (book)
    		if ("".equals(name)) {
    			name = Conventions.getVariableNameForParameter(methodParam);
    		}
    		Class<?> paramType = methodParam.getParameterType();
    		Object bindObject;
      	//       
    		if (implicitModel.containsKey(name)) {
    			bindObject = implicitModel.get(name);
    		}
      	// sessionAttribute  ,     ,    
    		else if (this.methodResolver.isSessionAttribute(name, paramType)) {
    			bindObject = this.sessionAttributeStore.retrieveAttribute(webRequest, name);
    			if (bindObject == null) {
    				raiseSessionRequiredException("Session attribute '" + name + "' required - not found in session");
    			}
    		}
    		else {
    			bindObject = BeanUtils.instantiateClass(paramType);
    		}
    		WebDataBinder binder = createBinder(webRequest, bindObject, name);
    		initBinder(handler, name, binder, webRequest);
    		return binder;
    	}
    
    SpringMVCはPOJO値の三段階を確定します。
  • もし暗黙のモデルがatrNameという値を持つなら、それです。
  • そうでなければ、この変数はSession Attributeに表示されている属性ではないかと思います。値がなければ、投げ異常
  • です。
  • いずれもそうでない場合は、反射により空のオブジェクト
  • を作成する。
    (6)パラメータ決定のまとめ(難点)
    まとめ:
  • 注解があるかどうかを見てください。ある話は解決注
  • です。
  • 注釈がない場合:
  • 元のAPIがあるかどうかを見てください。
  • ModelやMapなどのタイプかどうか見てください。
  • は全部違います。簡単なタイプかどうか、paramName="
  • "
  • はatrNameに値を割り当て、atrName(パラメータが表示されています@ModelAttribute(“”)は指定されています。ラベルがないのは“”です。カスタムタイプのパラメータを確定します。
     1. attrName             ,      @ModelAttribute("")  
     2.       `implicitModel`      key    
     3.     @SessionAtrribute     ,    Session  ,          
     4.   @SessionAtrribute     ,         ,       (WebDataBinder)