How tomcat works 读书笔记十二 StandardContext 下

来源:互联网 发布:windows sftp 密钥 编辑:程序博客网 时间:2024/06/11 17:48

对重载的支持

tomcat里容器对重载功能的支持是依靠Load的(在目前就是WebLoader)。当在绑定载入器的容器时
    public void setContainer(Container container) {              ...        // Register with the new Container (if any)        if ((this.container != null) && (this.container instanceof Context)) {            setReloadable( ((Context) this.container).getReloadable() );            ((Context) this.container).addPropertyChangeListener(this);        }    }
可见载入器的reloadable与它所绑定的容器的reloadable是一致的。
我们再看看载入器的setReloadable
 public void setReloadable(boolean reloadable) {        // Process this property change        boolean oldReloadable = this.reloadable;        this.reloadable = reloadable;      ....        if (!started)            return;        if (!oldReloadable && this.reloadable)  //            threadStart();        else if (oldReloadable && !this.reloadable)            threadStop();    }
之前在第八章的时候,我们就知道congext容器reloadable的默认值是false,而且载入器的reloadable也是false。
因而默认情况下,载入器的run方法不会运作。那载入器的start没有启动run方法么?
public void start() throws LifecycleException {               .....        // Start our background thread if we are reloadable        if (reloadable) {            log(sm.getString("webappLoader.reloading"));            try {                threadStart();            } catch (IllegalStateException e) {                throw new LifecycleException(e);            }        }    }
而载入器的run方法干什么?就是用
        while (!threadDone) {            // Wait for our check interval            threadSleep();            if (!started)                break;            try {                // Perform our modification check                if (!classLoader.modified())     //WebappClassLoader的modified是根据时间判定所监                        continue;                    //控的class是否改变            } catch (Exception e) {              //一旦改变了 返回true 就 notifyContext                log(sm.getString("webappLoader.failModifiedCheck"), e);                continue;            }            // Handle a need for reloading            notifyContext();            break;        }
notifyContext()会启用WebappContextNotifier,后者调用容器的reload方法。
不过上面说了这么多,前提条件是载入器的reloadable得是true....

backgroundProcess 方法

在tomcat5中(上面说的那些是基于tomcat4的),关于时间戳的检查交给了backgroundProcess。
现在有个问题,4里好好的,为什么到5里就改了呢?
改是有原因的嘛。
想想之前,session因为要检查过期时间得启用一个线程,关于重载得检查时间戳,还得启用一个线程...
因而,在tomcat5中,所以的后台处理程序共用一个线程。具体怎么办呢?听老夫给你细细道来。
后面的所有代码来自tomcat7.0.55
在tomcat中,ContainerBase里面有
    protected void threadStart() {        if (thread != null)            return;        if (backgroundProcessorDelay <= 0)            return;        threadDone = false;        String threadName = "ContainerBackgroundProcessor[" + toString() + "]";        thread = new Thread(new ContainerBackgroundProcessor(), threadName);        thread.setDaemon(true);        thread.start();    }
重启了一个线程,不用说关键问题就是ContainerBackgroundProcessor。而它是ContainerBase的一个内部类。
ContainerBackgroundProcessor在run方法里会周期性的调用processChildren方法。 protected void processChildren(Container container, ClassLoader cl) {       ...                container.backgroundProcess();           ...            Container[] children = container.findChildren();            for (int i = 0; i < children.length; i++) {                if (children[i].getBackgroundProcessorDelay() <= 0) {                    processChildren(children[i], cl);                }            }}
processChildren会先调用自己的backgroundProcess,然后让自己的子孙们也走一遍自己的流程。
   public void backgroundProcess() {                if (!getState().isAvailable())            return;        if (loader != null) {            try {                loader.backgroundProcess();     //载入器的后台程序            } catch (Exception e) {                log.warn(sm.getString("containerBase.backgroundProcess.loader", loader), e);                            }        }        if (manager != null) {            try {                manager.backgroundProcess();    //session的后台程序            } catch (Exception e) {                log.warn(sm.getString("containerBase.backgroundProcess.manager", manager), e);              }        }}
那具体的载入器的backgroundProcess怎么写呢?如下
WebappLoader.java      public void backgroundProcess() {        if (reloadable && modified()) {            try {                Thread.currentThread().setContextClassLoader                    (WebappLoader.class.getClassLoader());                if (container instanceof StandardContext) {                    ((StandardContext) container).reload();                }            } finally {                if (container.getLoader() != null) {                    Thread.currentThread().setContextClassLoader                        (container.getLoader().getClassLoader());                }            }        } else {            closeJARs(false);        }    }






0 0