SpringMVC 启动doDispatch类解析

springmvc dodispatcher解析。
1、mappedHandler = getHandler(processedRequest); 查找对应的请求URL的mapperHandler

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;
}

hm.getHandler(request)方法会调用

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        Object handler = getHandlerInternal(request);
        if (handler == null) {
            handler = getDefaultHandler();
        }
        if (handler == null) {
            return null;
        }
        // Bean name or resolved handler?
        if (handler instanceof String) {
            String handlerName = (String) handler;
            handler = getApplicationContext().getBean(handlerName);
        }
        return getHandlerExecutionChain(handler, request);
    }

getHandlerInternal方法在AbstractHandlerMethodMapping中。(XML配置是mvc:annotation-driven才走这个类,如果这个没配置只配置了context:component-scan和@Controller注解走AbstractUrlHandlerMapping。)

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
        if (logger.isDebugEnabled()) {
            logger.debug("Looking up handler method for path " + lookupPath);
        }
        HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
        if (logger.isDebugEnabled()) {
            if (handlerMethod != null) {
                logger.debug("Returning handler method [" + handlerMethod + "]");
            }
            else {
                logger.debug("Did not find handler method for [" + lookupPath + "]");
            }
        }
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }

主要方法在这里:HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);

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);
        }
    }

该方法如果找到直接的匹配信息,则将这次请求的内容(包括请求方法方式等)进行比对。如果找不到,则通过handlerMethods新创建一个匹配信息。addMatchingMappings方法:

private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
        for (T mapping : mappings) {
            T match = getMatchingMapping(mapping, request);
            if (match != null) {
                matches.add(new Match(match, this.handlerMethods.get(mapping)));
            }
        }
    }

getMatchingMapping方法:

    @Override
    protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) {
        return info.getMatchingCondition(request);
    }

getMatchingCondition方法:

public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
        RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
        ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
        HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);
        ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);
        ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);

        if (methods == null || params == null || headers == null || consumes == null || produces == null) {
            return null;
        }

        PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request);
        if (patterns == null) {
            return null;
        }

        RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);
        if (custom == null) {
            return null;
        }

只分析第一个methodsCondition.getMatchingCondition(request);后面类似。

public RequestMethodsRequestCondition getMatchingCondition(HttpServletRequest request) {
        if (this.methods.isEmpty()) {
            return this;
        }
        RequestMethod incomingRequestMethod = getRequestMethod(request);
        if (incomingRequestMethod != null) {
            for (RequestMethod method : this.methods) {
                if (method.equals(incomingRequestMethod)) {
                    return new RequestMethodsRequestCondition(method);
                }
            }
        }
        return null;
    }

比较requestMethod方法名是否相同。比如post、put、delete等。
params是匹配请求参数、consumes匹配请求过来的类型,比如application/json等、produces类似。

if (methods == null || params == null || headers == null ||     consumes == null || produces == null) {
        return null;
}

如果其中有一个匹配不上,就返回null。
如果没有匹配上的话,会调用handleNoMatch方法。会调用RequestMappingInfoHandlerMapping.handleNoMatch方法。

    protected HandlerMethod handleNoMatch(Set<RequestMappingInfo> requestMappingInfos,
            String lookupPath, HttpServletRequest request) throws ServletException {

        Set<String> allowedMethods = new LinkedHashSet<String>(4);

        Set<RequestMappingInfo> patternMatches = new HashSet<RequestMappingInfo>();
        Set<RequestMappingInfo> patternAndMethodMatches = new HashSet<RequestMappingInfo>();

        for (RequestMappingInfo info : requestMappingInfos) {
            if (info.getPatternsCondition().getMatchingCondition(request) != null) {
                patternMatches.add(info);
                if (info.getMethodsCondition().getMatchingCondition(request) != null) {
                    patternAndMethodMatches.add(info);
                }
                else {
                    for (RequestMethod method : info.getMethodsCondition().getMethods()) {
                        allowedMethods.add(method.name());
                    }
                }
            }
        }

        if (patternMatches.isEmpty()) {
            return null;
        }
        else if (patternAndMethodMatches.isEmpty() && !allowedMethods.isEmpty()) {
            throw new HttpRequestMethodNotSupportedException(request.getMethod(), allowedMethods);
        }

requestMappingInfos有该Controller所有方法的请求路径和请求方法名称。info.getPatternsCondition().getMatchingCondition(request)先匹配请求的url是否符合,如过符合则校验请求的requestMethod名称和自己设置的是否相同。如果相同则向patternAndMethodMatches中添加数据。如果不匹配则会向allowedMethods中记录允许的requestMethod。比如采用REST方式的页面请求方式为PUT,但是方法的requestMapping设置的为method=RequestMethod.POST,则会向
allowedMethods中添加post。之后如果patternAndMethodMatches匹配为空而允许的allowedMethods不为空,则抛出不匹配异常。

    public HttpRequestMethodNotSupportedException(String method, String[] supportedMethods) {
        this(method, supportedMethods, "Request method '" + method + "' not supported");
    }

如果正常的话,则继续操作。

                // Determine handler for the current request.
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }

                // Determine handler adapter for the current request.
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

getHandlerAdapter找到对应的handler后,查看是否支持对应的handler适配器。没有的话则抛错。

    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        for (HandlerAdapter ha : this.handlerAdapters) {
            if (logger.isTraceEnabled()) {
                logger.trace("Testing handler adapter [" + ha + "]");
            }
            if (ha.supports(handler)) {
                return ha;
            }
        }
        throw new ServletException("No adapter for handler [" + handler +
                "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    }

没问题的话则进入:

// Actually invoke the handler.
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

ha.handle分为两种实现。一种是采用mvc:annotation-driven注解,该实现类是RequestMappingHandlerAdapter.handleInternal方法。另一种是context:component-scan自动注解,对应的方法为AnnotationMethodHandlerAdapter.handle。原理类似。
RequestMappingHandlerAdapter.handleInternal方法最后会进入invokeHandleMethod(request, response, handlerMethod)方法。

private ModelAndView invokeHandleMethod(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);

        AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
        asyncWebRequest.setTimeout(this.asyncRequestTimeout);

        final WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
        asyncManager.setTaskExecutor(this.taskExecutor);
        asyncManager.setAsyncWebRequest(asyncWebRequest);
        asyncManager.registerCallableInterceptors(this.callableInterceptors);
        asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

        if (asyncManager.hasConcurrentResult()) {
            Object result = asyncManager.getConcurrentResult();
            mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
            asyncManager.clearConcurrentResult();

            if (logger.isDebugEnabled()) {
                logger.debug("Found concurrent result value [" + result + "]");
            }
            requestMappingMethod = requestMappingMethod.wrapConcurrentResult(result);
        }

        requestMappingMethod.invokeAndHandle(webRequest, mavContainer);

        if (asyncManager.isConcurrentHandlingStarted()) {
            return null;
        }

        return getModelAndView(mavContainer, modelFactory, webRequest);
    }

其中里面的WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);方法为获取所有的initBinder方法。之后经过一系列配置组装,进入requestMappingMethod.invokeAndHandle(webRequest, mavContainer);

    public void invokeAndHandle(ServletWebRequest webRequest,
            ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {

        Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
        setResponseStatus(webRequest);
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {

        Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
        if (logger.isTraceEnabled()) {
            StringBuilder sb = new StringBuilder("Invoking [");
            sb.append(getBeanType().getSimpleName()).append(".");
            sb.append(getMethod().getName()).append("] method with arguments ");
            sb.append(Arrays.asList(args));
            logger.trace(sb.toString());
        }
        Object returnValue = doInvoke(args);
        if (logger.isTraceEnabled()) {
            logger.trace("Method [" + getMethod().getName() + "] returned [" + returnValue + "]");
        }
        return returnValue;
    }

getMethodArgumentValues是对请求的入参进行装配和组装。

private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {

        MethodParameter[] parameters = getMethodParameters();
        Object[] args = new Object[parameters.length];
        for (int i = 0; i < parameters.length; i++) {
            MethodParameter parameter = parameters[i];
            parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
            GenericTypeResolver.resolveParameterType(parameter, getBean().getClass());
            args[i] = resolveProvidedArgument(parameter, providedArgs);
            if (args[i] != null) {
                continue;
            }
            if (this.argumentResolvers.supportsParameter(parameter)) {
                try {
                    args[i] = this.argumentResolvers.resolveArgument(
                            parameter, mavContainer, request, this.dataBinderFactory);
                    continue;
                }
                catch (Exception ex) {
                    if (logger.isTraceEnabled()) {
                        logger.trace(getArgumentResolutionErrorMessage("Error resolving argument", i), ex);
                    }
                    throw ex;
                }
            }
            if (args[i] == null) {
                String msg = getArgumentResolutionErrorMessage("No suitable resolver for argument", i);
                throw new IllegalStateException(msg);
            }
        }
        return args;
    }

getMethodParameters()获取对应的requestMapping方法中请求的所有的入参的类型。比如:public ModelAndView testLogin(@RequestParam(“addrs”) ArrayList abc,ArrayList addrs,User user,UserInfo userInfo,String age,Double aa)。之后进入try中的

args[i] = this.argumentResolvers.resolveArgument(
                            parameter, mavContainer, request, this.dataBinderFactory);

方法。进入HandlerMethodArgumentResolverComposite.resolveArgument方法。

    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

        HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
        Assert.notNull(resolver, "Unknown parameter type [" + parameter.getParameterType().getName() + "]");
        return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
    }

之后进入RequestParamMethodArgumentResolver的父类AbstractNamedValueMethodArgumentResolver.resolveArgument方法中。

    public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

        Class<?> paramType = parameter.getParameterType();
        NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);

        Object arg = resolveName(namedValueInfo.name, parameter, webRequest);
        if (arg == null) {
            if (namedValueInfo.defaultValue != null) {
                arg = resolveDefaultValue(namedValueInfo.defaultValue);
            }
            else if (namedValueInfo.required && !parameter.getParameterType().getName().equals("java.util.Optional")) {
                handleMissingValue(namedValueInfo.name, parameter);
            }
            arg = handleNullValue(namedValueInfo.name, arg, paramType);
        }
        else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
            arg = resolveDefaultValue(namedValueInfo.defaultValue);
        }

        if (binderFactory != null) {
            WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
            arg = binder.convertIfNecessary(arg, paramType, parameter);
        }

        handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);

        return arg;
    }

Class paramType = parameter.getParameterType();获取参数的实际类型,比如ArrayList。
NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);获取该参数要转换的名字及required。例如:(@RequestParam(“addrs”) ArrayList abc。paramType等于ArrayList,namedValueInfo中的name=”addrs”,required默认为true。
Object arg = resolveName(namedValueInfo.name, parameter, webRequest);将页面中请求的类型转换。基本就是String和String[]两种。
之后是一些设置。然后进入

    if (binderFactory != null) {
            WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
            arg = binder.convertIfNecessary(arg, paramType, parameter);
        }

创建该Controller的initBinder。

public final WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName)
            throws Exception {
        WebDataBinder dataBinder = createBinderInstance(target, objectName, webRequest);
        if (this.initializer != null) {
            this.initializer.initBinder(dataBinder, webRequest);
        }
        initBinder(dataBinder, webRequest);
        return dataBinder;
    }

进入initBinder(dataBinder, webRequest)方法。

    public void initBinder(WebDataBinder binder, NativeWebRequest request) throws Exception {
        for (InvocableHandlerMethod binderMethod : this.binderMethods) {
            if (isBinderMethodApplicable(binderMethod, binder)) {
                Object returnValue = binderMethod.invokeForRequest(request, null, binder);
                if (returnValue != null) {
                    throw new IllegalStateException("@InitBinder methods should return void: " + binderMethod);
                }
            }
        }
    }

binderMethods是个List,该List中有该Controller的的全部initBinder方法。但是isBinderMethodApplicable方法会帮我们过滤。

protected boolean isBinderMethodApplicable(HandlerMethod initBinderMethod, WebDataBinder binder) {
        InitBinder annot = initBinderMethod.getMethodAnnotation(InitBinder.class);
        Collection<String> names = Arrays.asList(annot.value());
        return (names.size() == 0 || names.contains(binder.getObjectName()));
    }

如果自定义的initBinder方法没有指定特定的value,则默认为每个入参都会走这个公共的initBinder,用这里面的自定义registerCustomEditor。如果指定了,则入参包含时才走。例如:
@InitBinder
protected void initBinder(WebDataBinder binder),
@InitBinder(“user”)
public void initUser(WebDataBinder binder),
public ModelAndView testLogin(ArrayList<> abc,User user)
那么在组装abc时会进入initBinder,在组装user时会进入initUser和initBinder。
initBinder方法执行完成后,继续往下走执行。
arg = binder.convertIfNecessary(arg, paramType, parameter);该方法是对一些特殊类型进行自定义转换,最多的就是日期类型转换。
现在Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);基本分析完毕了。
之后就是进入方法中了Object returnValue = doInvoke(args);
再之后就是

    try {
            this.returnValueHandlers.handleReturnValue(
                    returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
        }

根据内容返回modelandview了。
暂时先写到这里,未完待续。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值