【Tomcat源码学习】3.应用管理

通过上一节我们完成了对容器进行了加载、初始化、启动,而对于应用的加载部分独立出来,本节进行单独的讲解
 

一、应用加载流程

1)应用识别,Context创建
  • 在Host启动后,会调用Host的监听HostConfig进行启动事件处理
  • HostConfig在监听到启动事件后,会分别尝试从context.xml下,wabapps下war,webapp下文件夹进行应用的读取,读取过程中通过Host的启停线程池(startStopExecutor)进行独立线程读取,读取最终结果生成Context对象并添加进入Host容器中。注意这里用到了Future<?>协同方式
  • 这里构建的Context仅包含如下基本参数(如:name,path,webappVersion,docBase),另外会给Context默认增加监听ContextConfig
 
2)应用加载,Context启动

    • Engine启动ContainerBackgroundProcessor线程进行对所有容器进行后台处理,即调用所有容器的backgroundProcess()方法
    • 容器backgroundProcess()方法处理完成后,通知相应的监听器(事件类型为Lifecycle.PERIODIC_EVENT)
    • HostConfig会根据Context是否启动,进行相应启动操作(context.start()),
    • Context启动过程如下:
      • 获取一个WebAppLoader,
      • 应用类加载,执行WebAppLoader.start()方法,该方法内,会创建一个ClassLoader(WebappClassLoader),在调用ClassLoader.start()方法进行jar与class的加载
      • 添加应用级监听器至Context成员变量中,其中主要有:ServletContextAttributeListener,ServletRequestAttributeListener,ServletRequestListener,HttpSessionIdListener,HttpSessionAttributeListener,ServletContextListener,Context成员变量声明如下:
        private List<Object> applicationEventListenersList = new CopyOnWriteArrayList<>();
      • 执行SevletContextListener监听器上下文完成初始化方法(注意,Spring就是这里进行的初始化的)
    • Context启动完成后,通知相应的监听器ContextConfig,进行启动完成处理
    • ContextConfig.start()方法(核心为调用webConfig()方法)
      • 读取/WEB-INF/web.xml文件,构建WebXml对象
      • 解析所有class,判断是否有使用servlet相关注解(Ljavax/servlet/annotation/WebServlet),如果使用就注解对象手动添加至WebXml对象中,即生成ServletDef定义文件
      • 将jsp转换为ServletDef定义文件,并添加至WebXml对象中
      • 将WebXml对象内容解析至Context对象中(方法:configcontext),一个Servlet对应一个Wrapper容器
        for (Entry<String, String> entry : webxml.getContextParams().entrySet()) {
            context.addParameter(entry.getKey(), entry.getValue());
        }//context全局参数
        ....
        for (ErrorPage errorPage : webxml.getErrorPages().values()) {
            context.addErrorPage(errorPage);
        }//404页面
        for (FilterDef filter : webxml.getFilters().values()) {
            if (filter.getAsyncSupported() == null) {
                filter.setAsyncSupported("false");
            }
            context.addFilterDef(filter);
        }//拦截器
        for (FilterMap filterMap : webxml.getFilterMappings()) {
            context.addFilterMap(filterMap);
        }//拦截器Map
        context.setJspConfigDescriptor(webxml.getJspConfigDescriptor());
        for (String listener : webxml.getListeners()) {
            context.addApplicationListener(listener);
        }//监听器
       ......
        for (ServletDef servlet : webxml.getServlets().values()) {
            Wrapper wrapper = context.createWrapper();//一个servlet对应一个封装器Wrapper
            // Description is ignored
            // Display name is ignored
            // Icons are ignored
            // jsp-file gets passed to the JSP Servlet as an init-param
            if (servlet.getLoadOnStartup() != null) {
                wrapper.setLoadOnStartup(servlet.getLoadOnStartup().intValue());
            }
            if (servlet.getEnabled() != null) {
                wrapper.setEnabled(servlet.getEnabled().booleanValue());
            }
            wrapper.setName(servlet.getServletName());
            Map<String,String> params = servlet.getParameterMap();
            for (Entry<String, String> entry : params.entrySet()) {
                wrapper.addInitParameter(entry.getKey(), entry.getValue());
            }
            wrapper.setRunAs(servlet.getRunAs());
            Set<SecurityRoleRef> roleRefs = servlet.getSecurityRoleRefs();
            for (SecurityRoleRef roleRef : roleRefs) {
                wrapper.addSecurityReference(
                        roleRef.getName(), roleRef.getLink());
            }
            wrapper.setServletClass(servlet.getServletClass());
            MultipartDef multipartdef = servlet.getMultipartDef();
            if (multipartdef != null) {
                if (multipartdef.getMaxFileSize() != null &&
                        multipartdef.getMaxRequestSize()!= null &&
                        multipartdef.getFileSizeThreshold() != null) {
                    wrapper.setMultipartConfigElement(new MultipartConfigElement(
                            multipartdef.getLocation(),
                            Long.parseLong(multipartdef.getMaxFileSize()),
                            Long.parseLong(multipartdef.getMaxRequestSize()),
                            Integer.parseInt(
                                    multipartdef.getFileSizeThreshold())));
                } else {
                    wrapper.setMultipartConfigElement(new MultipartConfigElement(
                            multipartdef.getLocation()));
                }
            }
            if (servlet.getAsyncSupported() != null) {
                wrapper.setAsyncSupported(
                        servlet.getAsyncSupported().booleanValue());
            }
            wrapper.setOverridable(servlet.isOverridable());
            context.addChild(wrapper);
        }
        for (Entry<String, String> entry :
                webxml.getServletMappings().entrySet()) {
            context.addServletMapping(entry.getKey(), entry.getValue());
        }
        //sesseionConfig对象
        SessionConfig sessionConfig = webxml.getSessionConfig();
        if (sessionConfig != null) {
            if (sessionConfig.getSessionTimeout() != null) {
                context.setSessionTimeout(
                        sessionConfig.getSessionTimeout().intValue());
            }
            SessionCookieConfig scc =
                context.getServletContext().getSessionCookieConfig();
            scc.setName(sessionConfig.getCookieName());
            scc.setDomain(sessionConfig.getCookieDomain());
            scc.setPath(sessionConfig.getCookiePath());
            scc.setComment(sessionConfig.getCookieComment());
            if (sessionConfig.getCookieHttpOnly() != null) {
                scc.setHttpOnly(sessionConfig.getCookieHttpOnly().booleanValue());
            }
            if (sessionConfig.getCookieSecure() != null) {
                scc.setSecure(sessionConfig.getCookieSecure().booleanValue());
            }
            if (sessionConfig.getCookieMaxAge() != null) {
                scc.setMaxAge(sessionConfig.getCookieMaxAge().intValue());
            }
            if (sessionConfig.getSessionTrackingModes().size() > 0) {
                context.getServletContext().setSessionTrackingModes(
                        sessionConfig.getSessionTrackingModes());
            }
        }
    • 从WebApp加载中读取ServletContainerInitializer的实现,并添加至context容器中
 
    至此,host下面的context,wrapper,等容器就就已经生成并初始化了。





原文地址:https://www.cnblogs.com/hframe/p/5326352.html