美文网首页
Spring mvc容器启动

Spring mvc容器启动

作者: sarafina527 | 来源:发表于2018-08-23 14:05 被阅读0次

    Spring web容器

    Spring MVC项目启动时会有两个ApplicationContext容器,Root ApplicationContext用于管理Service层及以下层的bean,而dispacherServlet ApplicationContext用于管理Controller层的bean。

    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>应用名称</display-name>
        <!-- 用于spring容器初始化时读取配置 -->
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath*:META-INF/spring/applicationContext-*.xml</param-value>
        </context-param>
        <!-- 创建Spring容器 -->
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
        <!-- SpringMVC前端控制器 -->
        <servlet>
            <servlet-name>DispatcherServlet</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <!-- 用于spring 控制器容器配置 -->
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>WEB-INF/spring/webmvc-config.xml</param-value>
            </init-param>
            <init-param>
                <param-name>contextClass</param-name>
                <param-value>
                    org.springframework.web.context.support.AnnotationConfigWebApplicationContext
                </param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>DispatcherServlet</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    </web-app>
    
    

    解析:
    web.xml中注册了ContextLoaderListener实现了 ServletContextListener
    ServletContextListener接口有如下方法,会在servlet容器初始化和销毁的时候回调

    public interface ServletContextListener extends EventListener {
        void contextInitialized(ServletContextEvent var1);
        void contextDestroyed(ServletContextEvent var1);
    }
    

    监听器会在servlet容器启动和销毁时回调以上两个方法。
    ContextLoaderListener就是在contextInitialized方法中创建、初始化Root ApplicationContext的。

    1.Root ApplicationContext容器启动

    (1)ContextLoaderListener 方式:

    继承了ContextLoader
    servlet容器如tomcat启动时回调contextInitialized()

    ContextLoaderListener.contextInitialized(event)
        ContextLoader.initWebApplicationContext(event.getServletContext());
            ContextLoader.createWebApplicationContext(sc)// 从web.xml中获取contextClass参数(上文的AnnotationConfigWebApplicationContext),找到相应类,实例化,并设置其ServletContext
    
    

    由此创建了 Root WebApplicationContext。

    (2)WebApplicationInitializer方式:

    实现WebApplicationInitializer

    public class MyWebApplicationInitializer implements WebApplicationInitializer {
    
        @Override
        public void onStartup(ServletContext servletCxt) {
    
            // 创建AC并加载配置
            AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
            ac.register(AppConfig.class);
            ac.refresh();//abstractRefrshAC 创建BeanFactory并创建Bean和装配
    
            // 创建 DispatcherServlet 并注册
            DispatcherServlet servlet = new DispatcherServlet(ac);
            ServletRegistration.Dynamic registration = servletCxt.addServlet("app", servlet);
            registration.setLoadOnStartup(1);
            registration.addMapping("/app/*");
            // Servlet容器启动的时候会初始化DispatcherServlet.init会启动子AC
        }
    }
    

    启动流程:
    StandardContext是tomcat的容器组件,是servlet容器,在tomcat启动时会顶级容器Server会掌管子容器的生命周期,层层启动,Servlet 3.0规范在StandardContext.startInternal()时会查找启动Spring相关的,如下调用关系:

    StandardContext.startInternal()
        // servlet 3.0容器 容器启动时会查找ServletContainerInitializer这个接口的实现类启动
        SpringServletContainerInitializeron.Startup()
        // 实现ServletContainerInitializer,会查找WebApplicationInitializer实现类
            XXWebApplicationInitializer.Startup()
    

    2.DispatcherServlet实例化+初始化

    DispatcherServlet由tomcat时启动容器管理其生命周期调用init()方法初始化
    继承FrameworkServlet,FrameworkServlet继承ServletBean

    DispatcherServlet.init() //继承自祖父HttpServletBean
        FrameworkServlet.initServletBean()
        FrameworkServlet.initWebApplicationContext()
            FrameworkServlet.createWebApplicationContext()//创建AC并设置parent
                FrameworkServlet.configureAndRefreshWebApplicationContext()
                    wac.refresh();
            DispatcherServlet.onRefresh(webac)
                DispatcherServlet.initMultipartResolver(context);
                DispatcherServlet.initLocaleResolver(context);
                DispatcherServlet.initThemeResolver(context);
                DispatcherServlet.initHandlerMappings(context);
                DispatcherServlet.initHandlerAdapters(context);
                DispatcherServlet.initHandlerExceptionResolvers(context);
                DispatcherServlet.initRequestToViewNameTranslator(context);
                DispatcherServlet.initViewResolvers(context);
                DispatcherServlet.initFlashMapManager(context);
    

    如此创建好了

    4.为什么要有两个ApplicationContext

    (1)隔离 由于管理Controller层的子AC可以委托双亲 ApplicationContext去查找bean,所以Root ApplicationContext容器中的Bean是共享的,而子AC中的Bean却不能被管理下层Service层和DAO层的Root Application获取,从而达到上层依赖下层的纯粹性。

    相关文章

      网友评论

          本文标题:Spring mvc容器启动

          本文链接:https://www.haomeiwen.com/subject/xgkpiftx.html