springMVC 源码解读

    spring作为java开发最常用的框架之一,主要优势在与可以很容易的与第三方框架整合,在早起的web开发环境中常用的组合
是SSH即 struts+ spring + Hibernate,后来演变为SSM 即struts + spring + Mybatis,后来spring推出springMVC模块,
来完成web项目的开发,因为spring官方的支持使得在与spring进行整合的时候异常简单,而且在使用的时候也比struts方便,所以
越来越多的的项目使用springMVC替换struts,下面就springMVC的源码做一下简单的分析

一:主要概念

    HandlerAdapter:根据Handler来找到支持它的 HandlerAdapter,通过HandlerAdapter执行这个Handler
得到 ModelAndView 对象
    handler:具体的请求处理方法包含类及方法
    handlerMapping:我们在controller的方法是添加的requestMapping信息,在容器启动的时候,通过容器扫描生成
RequestMappingInfo信息,里面包括请求的方法方式参数及参数的顺序等信息放入handlerMapping中,
可以通过handerMapping 获取hander

二 :springMVC的启动

    作为一个传统的web项目,Servlet容器的启动是已web.xml文件中的配置为基础的,在springMVC项目的web.xml文件中
通常会配置一个dispatcherServlet对所有的请求做转发处理 DispatcherServlet的继承关系如下

这里写图片描述
项目在spring容器启动后根据web.xml文件的配置启动DispatcherServlet的初始化调用的是HttpServletBean中的init方法,

public final void init() throws ServletException {
        if (logger.isDebugEnabled()) {
            logger.debug("Initializing servlet '" + getServletName() + "'");
        }
        // Set bean properties from init parameters.
        PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
        if (!pvs.isEmpty()) {
            try {
            //配置文件加载
                BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
                ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
                bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
                initBeanWrapper(bw);
                bw.setPropertyValues(pvs, true);
            } catch (BeansException ex) {
                if (logger.isErrorEnabled()) {
                    logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
                }
                throw ex;
            }
        }
        //由子类FrameworkServlet提供具体实现
        initServletBean();
        if (logger.isDebugEnabled()) {
            logger.debug("Servlet '" + getServletName() + "' configured successfully");
        }
    }

在FrameworkServlet的initServletBean方法中先看 this.webApplicationContext = initWebApplicationContext() 这行代码 我们来看下initWebApplicationContext() 方法

protected WebApplicationContext initWebApplicationContext() {

        WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
        WebApplicationContext wac = null;
        //WebApplicationContext 因为实现了ApplicationContextAware接口 会在容器启动后注入spring的上下文applicationContext
        if (this.webApplicationContext != null) {
            wac = this.webApplicationContext;
            if (wac instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
                if (!cwac.isActive()) {
                    if (cwac.getParent() == null) { 
                        //设定当前MVC容器的父容器
                        cwac.setParent(rootContext);
                    }
                    configureAndRefreshWebApplicationContext(cwac);
                }
            }
        }
        if (wac == null) { 
            wac = findWebApplicationContext();
        }
        if (wac == null) { 
            wac = createWebApplicationContext(rootContext);
        } 
        if (!this.refreshEventReceived) { 
            //刷新容器 由子类DispatcherServlet实现只有一行代码 initStrategies(context);
            onRefresh(wac);
        }
        if (this.publishContext) { 
            String attrName = getServletContextAttributeName();
            getServletContext().setAttribute(attrName, wac); 
        } 
        return wac;
    }

在DispatcherServlet的onRefresh方法中只有一行代码 initStrategies(context) ,在此方法中完成springMVC中九大组件的注册

protected void initStrategies(ApplicationContext context) {
    initMultipartResolver(context);//用于处理上传请求
    initLocaleResolver(context);
    initThemeResolver(context);//主题解析器
    initHandlerMappings(context);//handlerMapping 解析器
    initHandlerAdapters(context);//handler解析具体的方法
    initHandlerExceptionResolvers(context);//异常解析
    initRequestToViewNameTranslator(context);//请求到视图的解析
    initViewResolvers(context);//视图解析器
    initFlashMapManager(context);// 用来管理FlashMap的,FlashMap主要用在redirect中传递参数
}
至此 springMVC容器的启动完成

三:请求响应

    在客户端发送http请求时会被DispatcherServlet中的doService方法拦截,在doService方法中完成请求上下文的
参数处理后调用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 {
                //检查是否为上传请求
                processedRequest = checkMultipart(request);
                multipartRequestParsed = (processedRequest != request);
                //更具request处理链 拦截器过以及具体的处理方法
                mappedHandler = getHandler(processedRequest);
                //url 未找到处理请求的handler的处理
                if (mappedHandler == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }.
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
                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;
                    }
                }
                //拦截器中的preHandle不通过是的处理
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }
                //通过反射执行具体的请求
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }
                //视图
                applyDefaultViewName(processedRequest, mv);
                //执行拦截器中的 postHandle不通过是的处理
                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);
                }
            }
        }
    }

至此请求处理完成

`

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值