The backgroundProcess Method
A context needs the help of other components, such as a loader and a manager. Often these components require a separate thread that handles background processing. For instance, a loader that support auto reload needs a thread to periodically check the timestamps of all class and JAR files in WEB-INF. A manager needs to a thread to check the expiration time of the session objects it manages. In Tomcat 4 those components end up having their own threads.
To save resources, Tomcat 5 uses a different approach. All background processes share the same thread. If a component or a Container needs to have an operation done periodically, all it needs to do is write the code in its backgroundProcess method.
The shared thread is created in a ContainerBase object. The ContainerBase class calls its threadStart method in its start method.
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(); }
The threadStart method constructs a new thread by passing an instance of ContainerBackgroundProcessor class that implements java.lang.Runnable.
protected class ContainerBackgroundProcessor implements Runnable{ public void run(){ while(!threadDone){ try{Thread.sleep(backgroundProcessorDelay*1000L);}catch(InterruptedException e){;} } if(!threadDone){ Container parent = getMappingObject(); ClassLoader cl = Thread.currentThread().getContextClassLoader(); if(parent.getLoader()!=null){ cl = parent.getLoader().getClasssLoader(); } processChildren(parent,cl); } } } protected void processChildren(Container container,ClassLoader cl){ try{ if(container.getLoader()!=null){ Thread.currentThread().setContextClassLoader(container.getLoader().getClassLoader())); }//设置线程变量 container.backgroundProcess();//execute逻辑 }catch(Throwable 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);//递归调用 } } }
The ContainerBackgroundProcessor class is an inner class of ContainerBase. Inside its run method is while loop that periodically calls its processChildren method. The processChildren method in turn calls the** backgroundProcess method and the **processChildren method of each of its children. By implementing the backgroundProcess method, a child class of ContainerBase can have a dedicated thread for running periodic tasks, such as checking classes’timestamps or expiry times of session objects.
public void backgroundProcess(){ if(!started) return; count = (count + 1)%managerChecksFrequency; if((getManager()!=null) &&(count ==0)){ try{ getManager().backgroundProcess();//session 管理 }catch(Exception e){ log.warn("Unable to perform background process on manager", x); } } if(getLoader()!=null){ if(reloadable && (getLoader().modified())){ try{ Thread.currentThread().setContextClassloader(StandardContext.class.getClassLoader()); reload();//现成使用最新的加载器 reload }finally{ if(getLoader()!=null){ Thread.currentThread().setContextClassLoader(getLoader().getClassLoader()); } } } if(getLoader() instanceof WebappLoader){ ((WebappLoader)getLoader()).closeJARs(false)); } } }
It should be clear how StandardContext helps its associated manager and loader with their periodic tasks.//context帮助他们周期性完成tasks