博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Tomcat学习笔记(十一)
阅读量:5364 次
发布时间:2019-06-15

本文共 10579 字,大约阅读时间需要 35 分钟。

 

StandardContext类 

  Context实例代表着一个具体的web应用程序,其中包含一个或者多个Wrapper实例,每个Wrapper实例代表着具体的servlet定义。但是,Context容器还需要其他组件支持,典型的如载入器和session管理器。

          

在创建了StandardContext实例后,必须调用其startInternal方法。 

(1)发送启动状态通知。

// Send j2ee.state.starting notification         if (this.getObjectName() != null) {            Notification notification = new Notification("j2ee.state.starting",                    this.getObjectName(), sequenceNumber.getAndIncrement());            broadcaster.sendNotification(notification);        }

(2)设置配置状态

setConfigured(false);public void setConfigured(boolean configured) {        boolean oldConfigured = this.configured;        this.configured = configured;        support.firePropertyChange("configured",                                   oldConfigured,                                   this.configured);    }

(3)加载资源

if (webappResources == null) {   // (1) Required by Loader            if (log.isDebugEnabled())                log.debug("Configuring default Resources");            try {                if (getDocBase() == null)                    setResources(new EmptyDirContext());                else if ((getDocBase() != null) && (getDocBase().endsWith(".war")) &&                        (!(new File(getBasePath())).isDirectory()))                    setResources(new WARDirContext());                else                    setResources(new FileDirContext());            } catch (IllegalArgumentException e) {                log.error(sm.getString("standardContext.resourcesInit"), e);                ok = false;            }        }

(4)初始化字符集mapper

// Initialize character set mapper        getCharsetMapper();

(5)设置工作目录

// Post work directory        postWorkDirectory();

6)绑定线程

// Binding thread        ClassLoader oldCCL = bindThread();

(7)通知监听器,启动子容器,开启管道中的阀门

// Notify our interested LifecycleListeners                fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null);                // Start our child containers, if not already started                for (Container child : findChildren()) {                    if (!child.getState().isAvailable()) {                        child.start();                    }                }                // Start the Valves in our pipeline (including the basic),                // if any                if (pipeline instanceof Lifecycle) {                    ((Lifecycle) pipeline).start();                }

(8)加载资源到servletContext和资源映射

// We put the resources into the servlet context        if (ok)            getServletContext().setAttribute                (Globals.RESOURCES_ATTR, getResources());        // Initialize associated mapper        mapper.setContext(getPath(), welcomeFiles, resources);

(9)创建context属性设置初始参数

// Create context attributes that will be required            if (ok) {                getServletContext().setAttribute(                        JarScanner.class.getName(), getJarScanner());            }            // Set up the context init params            mergeParameters();

(10)servlet容器初始化,配置事件监听

for (Map.Entry
>> entry : initializers.entrySet()) { try { entry.getKey().onStartup(entry.getValue(), getServletContext()); } catch (ServletException e) { log.error(sm.getString("standardContext.sciFail"), e); ok = false; break; } } // Configure and call application event listeners if (ok) { if (!listenerStart()) { log.error(sm.getString("standardContext.listenerFail")); ok = false; } }

(11)启动Manager

try {                // Start manager                if ((manager != null) && (manager instanceof Lifecycle)) {                    ((Lifecycle) getManager()).start();                }            } catch(Exception e) {                log.error(sm.getString("standardContext.managerFail"), e);                ok = false;            }            // Configure and call application filters            if (ok) {                if (!filterStart()) {                    log.error(sm.getString("standardContext.filterFail"));                    ok = false;                }            }            // Load and initialize all "load on startup" servlets            if (ok) {                if (!loadOnStartup(findChildren())){                    log.error(sm.getString("standardContext.servletFail"));                    ok = false;                }            }            // Start ContainerBackgroundProcessor thread            super.threadStart();

(12)通知启动状态,重新检查是否启动成功。

// Send j2ee.state.running notification         if (ok && (this.getObjectName() != null)) {            Notification notification =                 new Notification("j2ee.state.running", this.getObjectName(),                                 sequenceNumber.getAndIncrement());            broadcaster.sendNotification(notification);        }        // Close all JARs right away to avoid always opening a peak number         // of files on startup        if (getLoader() instanceof WebappLoader) {            ((WebappLoader) getLoader()).closeJARs(true);        }        // Reinitializing if something went wrong        if (!ok) {            setState(LifecycleState.FAILED);        } else {            setState(LifecycleState.STARTING);        }

StandardContextValve类 

实现了一个默认的阀门类,对于每一个HTTP请求可能是有用的。重要的方法invoke。 
(1)WEB-INF或META-INF目录下的资源访问不了的原因

// Disallow any direct access to resources under WEB-INF or META-INF        MessageBytes requestPathMB = request.getRequestPathMB();        if ((requestPathMB.startsWithIgnoreCase("/META-INF/", 0))                || (requestPathMB.equalsIgnoreCase("/META-INF"))                || (requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0))                || (requestPathMB.equalsIgnoreCase("/WEB-INF"))) {            response.sendError(HttpServletResponse.SC_NOT_FOUND);            return;        }

(2)获取一个Wrapper

// Select the Wrapper to be used for this Request        Wrapper wrapper = request.getWrapper();        if (wrapper == null || wrapper.isUnavailable()) {            response.sendError(HttpServletResponse.SC_NOT_FOUND);            return;        }

(3)认证request请求,调用Wrapper的阀门(valve)

// Acknowledge the request        try {            response.sendAcknowledgement();        } catch (IOException ioe) {            container.getLogger().error(sm.getString(                    "standardContextValve.acknowledgeException"), ioe);            request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, ioe);            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);            return;        }        if (request.isAsyncSupported()) {            request.setAsyncSupported(wrapper.getPipeline().isAsyncSupported());        }        wrapper.getPipeline().getFirst().invoke(request, response);

StandardContext对重载的支持 

        在类加载的指定的仓库下,类发生了改变或者web.xml文件发生了改变将会被重新加载,然而,不能处理任何context.xml文件的改变,如果context.xml发生了改变,应该停止指定的上下文(Context),并且创建和启动一个新的Context实例代替。 
在StandardContext中的reload方法中 
(1)检查组件是否可用

// Validate our current component state        if (!getState().isAvailable())            throw new IllegalStateException                (sm.getString("standardContext.notStarted", getName()));        if(log.isInfoEnabled())            log.info(sm.getString("standardContext.reloadingStarted",                    getName()));

(2)设置StandardContext暂停状态

// Stop accepting requests temporarily.setPaused(true);

(3)停止并启动

try {            stop();        } catch (LifecycleException e) {            log.error(                sm.getString("standardContext.stoppingContext", getName()), e);        }        try {            start();        } catch (LifecycleException e) {            log.error(                sm.getString("standardContext.startingContext", getName()), e);        }

(4)设置StandardContext暂停状态

setPaused(false);//设置非暂停状态

ContainerBackgroundProcessor类 

        Context容器运行还需要其他的组件支持,例如载入器和session管理器。通常这些组件都需要各自的线程执行一些后台处理任务。例如:载入器使用线程定时的检查类和jar的时间戳是否发生改变;session管理器使用线程定时检查session是否过期。 
        为了节省资源,所有后台共享同一个线程。若某个组件或者servlet容器需要周期性的执行一个操作,只需要将代码写到backgroundProcess方法中。 
ContainerBackgroundProcessor是ContainerBase的内部类,下面是代码:

protected class ContainerBackgroundProcessor implements Runnable {        @Override        public void run() {            Throwable t = null;            String unexpectedDeathMessage = sm.getString(                    "containerBase.backgroundProcess.unexpectedThreadDeath",                    Thread.currentThread().getName());            try {                while (!threadDone) {                    try {                    //sleep指定时间                        Thread.sleep(backgroundProcessorDelay * 1000L);                    } catch (InterruptedException e) {                        // Ignore                    }                    if (!threadDone) {                        Container parent = (Container) getMappingObject();                        ClassLoader cl =                             Thread.currentThread().getContextClassLoader();                        if (parent.getLoader() != null) {                            cl = parent.getLoader().getClassLoader();                        }                        processChildren(parent, cl);                    }                }            } catch (RuntimeException e) {                t = e;                throw e;            } catch (Error e) {                t = e;                throw e;            } finally {                if (!threadDone) {                    log.error(unexpectedDeathMessage, t);                }            }        }

processChildren方法

protected void processChildren(Container container, ClassLoader cl) {            try {                if (container.getLoader() != null) {                    Thread.currentThread().setContextClassLoader                        (container.getLoader().getClassLoader());                }                container.backgroundProcess();            } catch (Throwable t) {                ExceptionUtils.handleThrowable(t);                log.error("Exception invoking periodic operation: ", t);            } finally {                Thread.currentThread().setContextClassLoader(cl);            }            //获取所有的子容器,递归调用            Container[] children = container.findChildren();            for (int i = 0; i < children.length; i++) {                if (children[i].getBackgroundProcessorDelay() <= 0) {                    processChildren(children[i], cl);                }            }        }

 

转载于:https://www.cnblogs.com/lzeffort/p/7135379.html

你可能感兴趣的文章
洛谷 P1991 无线通讯网
查看>>
mysql asyn 示例
查看>>
数据库第1,2,3范式学习
查看>>
《Linux内核设计与实现》第四章学习笔记
查看>>
Docker 安装MySQL5.7(三)
查看>>
CF1067C Knights 构造
查看>>
CSS: caption-side 属性
查看>>
CSS3中box-sizing的理解
查看>>
Web.Config文件配置之配置Session变量的生命周期
查看>>
mysql导入source注意点
查看>>
linux下编译安装nginx
查看>>
DLL 导出函数
查看>>
windows超过最大连接数解决命令
查看>>
12个大调都是什么
查看>>
angular、jquery、vue 的区别与联系
查看>>
Intellij idea创建javaWeb以及Servlet简单实现
查看>>
代理网站
查看>>
Open multiple excel files in WebBrowser, only the last one gets activated
查看>>
FFmpeg进行视频帧提取&音频重采样-Process.waitFor()引发的阻塞超时
查看>>
最近邻与K近邻算法思想
查看>>