0
点赞
收藏
分享

微信扫一扫

How tomcat works 读书笔记十二 StandardContext 下


对重载的支持

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 条评论