SpringMVC设计原理与源码分析

1、SpringMvc调用的流程图:

 

2、SpringMvc核心对象描述

        ①DispatcherServlet为核心,负责请求的接受和处理及结果返回;

        ②HandlerMapping是url到Controller的映射组件,在容器初始化时按照Map<url, Controller>保存在容器中,从HandlerMapping中查找处理request的Controller组件;

         (实现: DispatchServlet接收到请求后,会根据顺序遍历Spring容器中的HandlerMapping对象(可以注册多个HandlerMapping处理器映射器对象),根据每个HandlerMapping对象的映射规则找到对应的处理器Controller和处理方法,如当遍历到RequestMappingHandlerMapping对象时,RequestMappingHandlerMapping对象会遍历容器中的所有使用了@Controller注解的bean,在根据@RequestMapping注解和url进行匹配,找到对应的Controller对象并根据url的匹配@RequestMapping上的处理方法。当找到合适的Controller和处理方法后,则停止遍历HandlerMapping对象。)

        ③HandlerAdapter是处理器适配器,其功能就是将我们自定义的前端控制器Controller适配成DispatchServlet需要的接口,使用了适配器模式;

        (实现:DispatchServlet遍历HandlerMapping获取HandlerExecutionChain对象后,遍历spring容器中的所有HandlerAdapter对象,查看当前处理器适配器对象是否能够支持适配找到的处理器对象Controller,能则调用适配器的接口handle()方法处理请求,并进行参数绑定,参数绑定可以通过注解或参数名进行绑定处理前有拦截器的先执行拦截处理)

           常见的HandlerAdapter有:SimpleControllerHandlerAdapter、DefaultAnnotationHandlerAdapter、RequestMappingHandlerAdapter(定义和handler()方法进行处理使用注解@Controller和@RequestMapping 标识的处理器)

        ④Controller处理request,并返回ModelAndView(封装结果视图的组件)对象,

        ⑤ViewResolver进行视图解析将逻辑视图解析成物理页面文件。注意对于使用了@ResponseBody注解的方法,DispatchServlet会使用合适的消息转换器将请求处理结果转换后返回给前台。

 

3、SpringMVC源码分析

        一,ApplicationContext 初始化时建立所有url 和Controller 类的对应关系(用Map<url, Controller>保存);

              ApplicationObjectSupport # setApplicationContext()     真实实现在子类:AbstractDetectingUrlHandlerMapping

@Override
public void initApplicationContext() throws ApplicationContextException {
    super.initApplicationContext();
    detectHandlers();
}


/**
* 建立当前ApplicationContext 中的所有Controller 和url 的对应关系
*/
protected void detectHandlers() throws BeansException {
    ApplicationContext applicationContext = obtainApplicationContext();
    if (logger.isDebugEnabled()) {
        logger.debug("Looking for URL mappings in application context: " + applicationContext);
    }

    // 获取ApplicationContext 容器中所有bean 的Name
    String[] beanNames = (this.detectHandlersInAncestorContexts ?
    BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext,     Object.class) :
    applicationContext.getBeanNamesForType(Object.class));

    // 遍历beanNames,并找到这些bean 对应的url
    for (String beanName : beanNames) {
        // 找bean 上的所有url(Controller 上的url+方法上的url),该方法由对应的子类实现
        String[] urls = determineUrlsForHandler(beanName);
        if (!ObjectUtils.isEmpty(urls)) {
            // 保存urls 和beanName 的对应关系,put it to Map<urls,beanName>,该方法在父类AbstractUrlHandlerMapping 中实现
            registerHandler(urls, beanName);
        } else {
            if (logger.isDebugEnabled()) {
                logger.debug("Rejected bean name '" + beanName + "': no URL paths identified");
            }
        }
    }
}

/** 获取Controller 中所有方法的url,由子类实现,典型的模板模式,BeanNameUrlHandlerMapping实现处理注解形式的url映射**/
protected abstract String[] determineUrlsForHandler(String beanName);



/**
* 获取Controller 中所有的url
*/
@Override
protected String[] determineUrlsForHandler(String beanName) {
    List<String> urls = new ArrayList<>();
    if (beanName.startsWith("/")) {
        urls.add(beanName);
    }
    String[] aliases = obtainApplicationContext().getAliases(beanName);
    for (String alias : aliases) {
        if (alias.startsWith("/")) {
            urls.add(alias);
        }
    }
    return StringUtils.toStringArray(urls);
}


        二,根据请求url 找到对应的Controller,并从Controller 中找到处理请求的方法;  入口:DispatcherServlet # 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.检查是否是文件上传的请求
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            // 2.取得处理当前请求的Controller,这里也称为hanlder,处理器,
            // 第一个步骤的意义就在这里体现了.这里并不是直接返回Controller,
            // 而是返回的HandlerExecutionChain 请求处理器链对象,
            // 该对象封装了handler 和interceptors.
            mappedHandler = getHandler(processedRequest);
            // 如果handler 为空,则返回404
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

            //3. 获取处理request 的处理器适配器handler adapter
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
            // 处理last-modified 请求头
            String Method = request.getMethod();
            boolean isGet = "GET".equals(Method);
            if (isGet || "HEAD".equals(Method)) {
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                if (logger.isDebugEnabled()) {
                    logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                }
                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                    return;
                }
            }
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }

            // 4.实际的处理器处理请求,返回结果视图对象
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
            if (asyncManager.isConcurrentHandlingStarted()) {
                return;
            }
            // 结果视图对象的处理
            applyDefaultViewName(processedRequest, mv);
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        } catch (Exception ex) {
            dispatchException = ex;
        } catch (Throwable err) {
            dispatchException = new NestedServletException("Handler dispatch failed", err);
        }
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    } catch (Exception ex) {
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    } catch (Throwable err) {
        triggerAfterCompletion(processedRequest, response, mappedHandler,
        new NestedServletException("Handler processing failed", err));
    } finally {
        if (asyncManager.isConcurrentHandlingStarted()) {
            if (mappedHandler != null) {
                // 请求成功响应之后的方法
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
        } else {
            if (multipartRequestParsed) {
                cleanupMultipart(processedRequest);
            }
        }
    }
}

             mappedHandler = getHandler(processedRequest);是获取Controller的关键


        三,request 参数绑定到方法的形参,执行方法处理请求,并返回结果视图.  handle的核心实现为

AbstractHandlerMethodAdapter类其调用父类实现:RequestMappingHandlerAdapter # 

handleInternal(request, response, handler)

             

/**RequestMappingHandlerAdapter  # handleInternal()*/
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    ModelAndView mav;
    checkRequest(request);
    if (this.synchronizeOnSession) {
        HttpSession session = request.getSession(false);
        if (session != null) {
            Object mutex = WebUtils.getSessionMutex(session);
            synchronized (mutex) {
                mav = invokeHandlerMethod(request, response, handlerMethod);
            }
        } else {
            mav = invokeHandlerMethod(request, response, handlerMethod);
        }
    } else {
        mav = invokeHandlerMethod(request, response, handlerMethod);
    }

    if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
        if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
            applyCacheSeconds(response, this.cac  heSecondsForSessionAttributeHandlers);
        } else {
            prepareResponse(response);
        }
    }
    return mav;
}




/** 获取处理请求的方法,执行并返回结果视图**/
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    ServletWebRequest webRequest = new ServletWebRequest(request, response);
    try {
        WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
        ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
        ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
        if (this.argumentResolvers != null) {
                invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
        }
        if (this.returnValueHandlers != null) {
        invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers)    ;
        }
        invocableMethod.setDataBinderFactory(binderFactory);
              invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
        ModelAndViewContainer mavContainer = new ModelAndViewContainer();
                mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
        modelFactory.initModel(webRequest, mavContainer, invocableMethod);
    mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
        AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
        asyncWebRequest.setTimeout(this.asyncRequestTimeout);
        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 + "]");
            }
            invocableMethod = invocableMethod.wrapConcurrentResult(result);
        }

        //调用实现request请求中的参数和方法参数上的数据绑定;
        //参数绑定有:注解绑定@RequestParam    和   参数名称绑定(通过asm框架获取参数中的名称--不推荐);
        invocableMethod.invokeAndHandle(webRequest, mavContainer);
        if (asyncManager.isConcurrentHandlingStarted()) {
            return null;
        }
        return getModelAndView(mavContainer, modelFactory, webRequest);
    } finally {
        webRequest.requestCompleted();
    }
}



@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
    //核心1:获取方法参数值
    Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);

    if (logger.isTraceEnabled()) {
        logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
"' with arguments " + Arrays.toString(args));
    }

    //核心2:反射调用实现controller的调用
    Object returnValue = doInvoke(args);
    if (logger.isTraceEnabled()) {
        logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
"] returned [" + returnValue + "]");
    }
    return returnValue;
}

//核心1、获取注解或者参数名对应的url中的参数值
private Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable 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);
        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.isDebugEnabled()) {
                    logger.debug(getArgumentResolutionErrorMessage("Failed to resolve", i), ex);
                }
                throw ex;
            }
        }

        if (args[i] == null) {
            throw new IllegalStateException("Could not resolve method parameter at index " +
parameter.getParameterIndex() + " in " + parameter.getExecutable().toGenericString() +
": " + getArgumentResolutionErrorMessage("No suitable resolver for", i));
        }
    }
    return args;
}




//核心2、反射实现调用
  protected Object doInvoke(Object... args) throws Exception {
        ReflectionUtils.makeAccessible(this.getBridgedMethod());

        try {
            //反射调用  
            return this.getBridgedMethod().invoke(this.getBean(), args);
        } catch (IllegalArgumentException var5) {
            this.assertTargetBean(this.getBridgedMethod(), this.getBean(), args);
            String message = var5.getMessage() != null ? var5.getMessage() : "Illegal argument";
            throw new IllegalStateException(this.getInvocationErrorMessage(message, args), var5);
        } catch (InvocationTargetException var6) {
            Throwable targetException = var6.getTargetException();
            if (targetException instanceof RuntimeException) {
                throw (RuntimeException)targetException;
            } else if (targetException instanceof Error) {
                throw (Error)targetException;
            } else if (targetException instanceof Exception) {
                throw (Exception)targetException;
            } else {
                String msg = this.getInvocationErrorMessage("Failed to invoke controller method", args);
                throw new IllegalStateException(msg, targetException);
            }
        }
    }

 

4、从源码阅读中得到平时使用SpringMVC的优化点:

①Controller使用单例,否则每次都会对Controller进行创建非常消耗性能

②在参数绑定中使用注解绑定@RequestParam,减少asm字节码的操作

③没有对url的方法进行缓存,每次都要根据url去匹配Controller,如果缓存起来要考虑url的线程安全问题;

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值