SpringMVC_DispatcherServlet源码分析

一、前端控制器的架构?DispatcherServlet在这里插入图片描述

二、doDispatch()详细细节:

	@RequestMapping("/updateBook")
	public String updateBook(@RequestParam(value="author")String author,
			Map<String, Object> model,
			HttpServletRequest request,
			@ModelAttribute("haha") Book book
			){
		o2 = model;
		b2  = book;
		Object haha = model.get("haha");
		//System.out.println("传入的model:"+model.getClass());
		System.out.println("o1==o2?"+(o1 == o2));
		System.out.println("b1==b2?"+(b1 == b2)+"-->"+(b2 == haha));
		
		System.out.println("页面要提交过来的图书信息:"+book);
		return "success";
	}


    //	@ModelAttribute("haha")
    @ModelAttribute
    public void hahaMyModelAttribute(Map<String, Object> map){

        Book book = new Book(100, "西游记", "吴承恩", 98, 10, 98.98);
        System.out.println("数据库中查到的图书信息是:"+book);
        map.put("book", book);
        b1 = book;
        o1 = map;
        System.out.println("modelAttribute方法...查询了图书并给你保存起来了...他用的map的类型:"+map.getClass());
    }

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、检查是否文件上传请求
                processedRequest = checkMultipart(request);
                multipartRequestParsed = processedRequest != request;

                // Determine handler for the current request.
               //2、根据当前的请求地址找到目标处理器(哪个Controller)类;

                mappedHandler = getHandler(processedRequest);

               //3、如果没有找到哪个处理器(控制器)能处理这个请求就404,或者抛异常
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);
                    return;

                }


                // Determine handler adapter for the current request.
               //4、拿到能执行这个类的所有方法的适配器;(反射工具AnnotationMethodHandlerAdapter)
                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;
                    }
                }
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }
                try {

                    // Actually invoke the handler.处理(控制)器的方法被调用
                    //控制器(Controller),处理器(Handler)
                    //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;转发到对应页面,而且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、所有请求过来DispatcherServlet收到请求,
2、调用doDispatch()方法进行处理

  • ①getHandler():根据当前请求地址找到能处理这个请求的目标处理器类(Controller类)根据当前请求在HandlerMapping中找到这个请求的映射信息,获取到目标处理器类
  • ②getHandlerAdapter():根据当前处理器类获取到能执行这个处理器方法的适配器;根据当前处理器类,找到当前类的HandlerAdapter(适配器)
  • ③使用刚才获取到的适配器(AnnotationMethodHandlerAdapter )执行目标方法;mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
  • ④目标方法执行后会返回一个ModelAndView对象
  • ⑤根据ModelAndView的信息转发到具体的页面,并可以在请求域中取出ModelAndView中的模型数据

三、getHandler()细节:怎么根据当前请求就能找到哪个类能来处理

HandlerMapping:处理器映射:他里面保存了每一个处理器能处理哪些请求的映射信息;
handlerMap:ioc容器启动创建Controller对象的时候扫描每个处理器(Controller)都能处理什么请求,保存在HandlerMapping的handlerMap属性中;
下一次请求过来,就来看哪个HandlerMapping中有这个请求映射信息就行了;

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;

    }

查看handlerMappings,有两个对象,【0】配置资源部 【1】注解资源部
在这里插入图片描述
getHandler()会返回目标处理器类的执行链;
在这里插入图片描述

四、getHandlerAdapter细节,如何找到目标处理器类的适配器,然后拿适配器才去执行目标方法

在这里插入图片描述
AnnotationMethodHandlerAdapter:能解析注解方法的适配器;处理器类(Controller类)中只要有标了注解的方法就能用;

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

    }

五、doDispatch()的适配器执行handle方法细节

1、handle里面return invokeHandlerMethod代码细节解析
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);
        //包装原生的request, response,
        ServletWebRequest webRequest = new ServletWebRequest(request, response);
          //创建了一个,隐含模型(implicit:含蓄的)
        ExtendedModelMap implicitModel = new BindingAwareModelMap();
        //真正执行目标方法;目标方法利用反射执行期间确定参数值,提前执行modelattribute等所有的操作都在这个方法中;            args:目标方法,处理器类,request和response的包装类,隐含模型
        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;

    }

在这里插入图片描述
在这里插入图片描述


2、invokeHandlerMethod方法执行的细节:
publicfinal Object invokeHandlerMethod(Method handlerMethod, Object handler,
            NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception {
        //获取到执行方法
        Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod);//目标方法
        try {
            boolean debug = logger.isDebugEnabled();
            //拿到所有的@SessionAttribute注解中所有的value(数组),遍历每一个value,
            for (String attrName : this.methodResolver.getActualSessionAttributeNames()) {
                //从sessionAttribute存储区中查询出来
                Object attrValue = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName);
                if (attrValue != null) {
        //隐含模型第一次有值
        //若@SessionAttribute标注的属性value在session中有值,他会把这些拿来放在隐含模型中
                    implicitModel.addAttribute(attrName, attrValue);

                }

            }
               
          //找到所有@ModelAttribute注解标注的方法;
            for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) {
            
                //遍历一个标了@ModelAttribute的方法

                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();//获取方法上标注的@ModelAttribute注解的value对应的key值   ,作为ModelAttribute方法的返回值,若没有则先把attrName设为“”,即空串
                if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) {
                    continue;
                }

                ReflectionUtils.makeAccessible(attributeMethodToInvoke);//利用反射把该方法置为可访问的
               
               //提前运行ModelAttribute,
                Object attrValue = attributeMethodToInvoke.invoke(handler, args);


                if ("".equals(attrName)) {//若attrName为空串,即方法上的@ModeAttribute没有value属性
                    Class<?> resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass());//解析并获取返回值类型
                    attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue);//为返回值类型起一个变量名,void 则为"void" Book返回值则为"book",返回值类型首字母小写
                

                }
                //把提前运行的ModelAttribute方法的返回值也放在隐含模型中
                if (!implicitModel.containsAttribute(attrName)) {
                    implicitModel.addAttribute(attrName, attrValue);
                }
                

            }

                                               //获取@ModleAttribute标记的方法的参数并且利用反射执行该方法后,就要执行目标方法了

               //再次解析目标方法参数是哪些值
            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;
        }

    }

1)、拿到所有的@SessionAttribute注解中所有的value(数组),遍历每一个value,若@SessionAttribute标注的属性value在session中有值,他会把这些拿来放在隐含模型中(隐含模型第一次有值)
2)、找到所有@ModelAttribute注解标注的方法,遍历
在这里插入图片描述

  • ①拿到第一个标了@ModelAttribute的方法,确定该方法执行时要使用的每一个参数的值(在后面会详细讲);

  • ②获取方法上标注的@ModelAttribute注解的value属性对应的key值 并且赋值给attrName,若没有value则先把attrName设为“”,即空串
    在这里插入图片描述
    在这里插入图片描述

  • ③利用反射把该方法置为可访问的然后利用反射提前运行该方法,并且得到方法运行结果的返回值 赋值给attrValue(null)
    在这里插入图片描述

  • ④若attrName为"" ,则解析方法并且获取方法的返回值类型,然后赋值attrName=返回值类型首字母小写(方法返回值void 则为"void" ,返回值Book则为"book")
    在这里插入图片描述

  • ⑤把提前运行的ModelAttribute方法的返回值放在隐含模型中 implicitModel.addAttribute(attrName, attrValue);
    在这里插入图片描述

3)、解析目标方法参数,然后执行目标方法
在这里插入图片描述
在这里插入图片描述


3、确定方法运行时使用的每一个参数的值resolveHandlerArguments方法代码解析(Object[] args = resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel);

这里就不示范@ModelAttribute的方法的参数确定(只有一个Map参数而已),直接示范目标方法的参数确定过程。
在这里插入图片描述

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++) {
            //整成SpringMVC可以处理的方法的参数
            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();
			//找到目标方法第i个参数的所有注解,如果有注解就解析并保存注解的信息;         
            for (Annotation paramAnn : paramAnns) {
                if (RequestParam.class.isInstance(paramAnn)) {
                    RequestParam requestParam = (RequestParam) paramAnn;
                    //拿到注解的value值,赋值给paremName;
                    paramName = requestParam.value();
                    //拿到注解的required值,赋值给required;
                    required = requestParam.required();
                    //拿到注解的defaultValue值,赋值给defaultValue;
                    defaultValue = parseDefaultValueAttribute(requestParam.defaultValue());
                    //解析成功,++
                    annotationsFound++;
                }
                else if (RequestHeader.class.isInstance(paramAnn)) {
                    RequestHeader requestHeader = (RequestHeader) paramAnn;
                    headerName = requestHeader.value();
                    required = requestHeader.required();
                    defaultValue = parseDefaultValueAttribute(requestHeader.defaultValue());
                    annotationsFound++;
                }
                else if (RequestBody.class.isInstance(paramAnn)) {
                    requestBodyFound = true;
                    annotationsFound++;
                }
                else if (CookieValue.class.isInstance(paramAnn)) {
                    CookieValue cookieValue = (CookieValue) paramAnn;
                    cookieName = cookieValue.value();
                    required = cookieValue.required();
                    defaultValue = parseDefaultValueAttribute(cookieValue.defaultValue());
                    annotationsFound++;
                }
                else if (PathVariable.class.isInstance(paramAnn)) {
                    PathVariable pathVar = (PathVariable) paramAnn;
                    pathVarName = pathVar.value();
                    annotationsFound++;
                }
                else if (ModelAttribute.class.isInstance(paramAnn)) {
                    ModelAttribute attr = (ModelAttribute) paramAnn;
                    attrName = attr.value();
                    annotationsFound++;
                }
                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) {
                //解析普通参数-->会进入resolveStandardArgument(解析标准参数)
                Object argValue = resolveCommonArgument(methodParam, webRequest);                           
                if (argValue != WebArgumentResolver.UNRESOLVED) {//参数不等于未解析,即解析成功(若解析失败,即当前的参数不是原生API,如当前为Map,则argValue的地址为WebArgumentResolver.UNRESOLVED)                                        
                    args[i] = argValue;//解析成功就赋值
                }
                else if (defaultValue != null) {
                    args[i] = resolveDefaultValue(defaultValue);
                }
                else {
                    Class<?> paramType = methodParam.getParameterType();
                    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;
                    }
                    else if (SessionStatus.class.isAssignableFrom(paramType)) {
                        args[i] = this.sessionStatus;
                    }
                    else if (HttpEntity.class.isAssignableFrom(paramType)) {
                        args[i] = resolveHttpEntityRequest(methodParam, webRequest);
                    }
                    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);//给参数绑定值,若有@ModelAttribute中找到参数的对象,则在该参数基础上进行参数的绑定
                }
                args[i] = binder.getTarget();
                if (assignBindingResult) {
                    args[i + 1] = binder.getBindingResult();
                    i++;
                }
                implicitModel.putAll(binder.getBindingResult().getModel());
            }
        }
        return args;
    }

过程如下:

1、获取到一个方法的所有参数
在这里插入图片描述

2、创建了一个和参数个数一样多的数组,会用来保存每一个参数的值 Object[] args = new Object[paramTypes.length];
在这里插入图片描述

3、遍历每个参数,解析参数类型
在这里插入图片描述

  • 找到当前方法当前遍历到的参数的所有注解,若有注解,解析并保存注解的信息; 如果参数有ModelAttribute注解;拿到ModelAttribute注解的值让attrName保存attrName=“haha”
    在这里插入图片描述
    实在写不下去了,太多了5555555,贴流程吧。。。
    在这里插入图片描述
   //确定值的环节
            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;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值