一、web.xml配置

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>



  <servlet>
    <servlet-name>springDispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>springDispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>


</web-app>

入口分析 

我们知道,在单独使用springmvc(不加入spring-context等组件)的时候,我们需要配置DispatcherServlet,那它是如何工作的呢,入口在哪?

通过查看DispatcherServlet,我们知道它实质是一个servlet,tomcat容器的启动(我们假设是用的tomcat),会启动我们的Servlet,执行init方法。

(注:DispatcherServlet继承了HttpServletBean,于是接下来我们就从init方法往下捋)

下面是代码执行步骤,也就是springmvc的执行流程

  1. HttpServletBean.init();//初始化方法

  2. FrameworkServlet.initServletBean();//初始化servlcet对象

  3. initWebApplicationContext

    1. FrameworkServlet.createWebApplicationContext(rootContext);//创建上下文

    2. FrameworkServlet.onRefresh(wac)-->DispatcherServlet.onRefresh(wac)

    3. DispatcherServlet.initStrategies(context);//初始化各种解析器(上传文件,国际化,映射器,适配器,日志等)

    4. DispatcherServlet.doService(request, response);//处理请求

    5. DispatcherServlet.doDispatch(request, response);//分发请求

      1. getHandler(processedRequest);//处理器映射器

      2.  this.getHandlerAdapter(mappedHandler.getHandler());//处理器适配器

      3.  ha.handle(...)//执行处理器逻辑

      4. applyDefaultViewName(processedRequest, mv);//视图渲染

二、和spirng融合

(注:上面是没有和spring融合,如果在ssm或者ssh的项目中)

我们在web.xml配置文件那里还会配置 ContextLoaderListener

文件如下

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <!-- 配置启动 Spring IOC 容器的 Listener -->
  <!-- needed for ContextLoaderListener -->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
  </context-param>

  <!-- Bootstraps the root web application context before servlet initialization -->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <servlet>
    <servlet-name>springDispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>springDispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>


</web-app>

初始化默认加载XmlWebApplicationContext根上下文 

ContextLoaderListener.contextInitialized

->
ContextLoaderListener.initWebApplicationContext

->

ContextLoaderListener.determineContextClass(sc);

->

defaultStrategies.getProperty(...)

->

ContextLoader.properties文件

ContextLoader.properties文件 

 org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext

protected Class<?> determineContextClass(ServletContext servletContext) {
    	// 若你在web.xml中设置的<context-param>里声明了
    	// contextClass的值,则直接利用反射得到其Class
        String contextClassName = servletContext.getInitParameter("contextClass");
        if (contextClassName != null) {
            try {
                return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
            } catch (ClassNotFoundException var4) {
                throw new ApplicationContextException("Failed to load custom context class [" + contextClassName + "]", var4);
            }
        } else {
        	// 这里返回XmlWebApplicationContext
            contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());

            try {
            	// 反射得到XmlWebApplicationContext.Class
                return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
            } catch (ClassNotFoundException var5) {
                throw new ApplicationContextException("Failed to load default context class [" + contextClassName + "]", var5);
            }
        }
    }

把spring容器作为父容器

在 DispatcherServlet 中也会创建一个 WebApplicationContext 我们称之为 子上下文,当执行dispatchServlet的创建上下文方法时,会把根容器上下文作为自己的父容器

protected WebApplicationContext initWebApplicationContext() {
        WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
        WebApplicationContext wac = null;
        if (this.webApplicationContext != null) {
            wac = this.webApplicationContext;
            if (wac instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)wac;
                if (!cwac.isActive()) {
                  //把根容器上下文放入自己的上下文容器中,所以我们把springmvc的容器称之为子容器
                    if (cwac.getParent() == null) {
                        cwac.setParent(rootContext);
                    }

                    this.configureAndRefreshWebApplicationContext(cwac);
                }
            }
        }
}

 

本文为本人总结的springmvc源码的流程,如果对您起动了一点点的帮助,请在下面点个小小的赞,将是对本人的很大鼓励!非常感谢

本文如有错误之处,望不吝指出,谢谢。

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐