开篇
Tomcat后台有周期性任务,包括一些过期任务等,这篇文章主要是想讲清楚后台周期性任务的启动和执行过程。
Tomcat容器关系图
-
1、要理解Tomcat的后台周期任务需要理解Tomcat的组件关系图以及容器的继承关系。
-
2、Tomcat的组件关系图说明了容器的启动过程,按照(Engine -> Host -> Context -> Wrapper)的顺序启动容器。
-
3、Tomcat的容器关系图说明ContainerBase的实现类,后台周期任务按照(Wrapper -> Context -> Host ->Engine)的顺序执行,但是除了Engine容器之外其他容器因为backgroundProcessorDelay的变量值为-1所以不会执行。
-
4、Tomcat的容器Engine在执行后台周期任务的过程中会递归链式调用(Host -> Context -> Wrapper)容器。
Tomcat 组件关系图
说明:
-
Tomcat各个容器的包含关系如上图。
-
各容器组件之间的包含关系如:StandardEngine -> StandardHost ->StandardContext -> StandardWrapper。
Tomcat容器关系图
image.png说明:
-
ContainerBase作为容器的基类,实现类StandardEngine、StandardHost、StandardContext、StandardWrapper。
-
ContainerBase基类的backgroundProcessorDelay 初始化为 -1;
-
StandardHost、StandardContext、StandardWrapper的backgroundProcessorDelay初始值为-1.
-
StandardEngine的重写backgroundProcessorDelay的值设为10。
public abstract class ContainerBase extends LifecycleMBeanBase implements Container {
protected int backgroundProcessorDelay = -1;
}
public class StandardEngine extends ContainerBase implements Engine {
public StandardEngine() {
super();
pipeline.setBasic(new StandardEngineValve());
try {
setJvmRoute(System.getProperty("jvmRoute"));
} catch(Exception ex) {
}
backgroundProcessorDelay = 10;
}
}
后台周期任务源码分析
容器和周期任务启动过程
-
1、ContainerBase的继承类StandardEngine、StandardHost、StandardContext、StandardWrapper。
-
2、上述的Engine、Host、Context、Wrapper类在启动过程中都会调用ContainerBase的startInternal()方法。
-
3、ContainerBase的startInternal()方法中,会启动本容器的Cluster、Realm等对象,然后递归执行Container children[] = findChildren()子容器,Engine调用Host、Host调用Context、Context调用Wrapper容器完成容器链路的启动。
-
4、按照递归调用的反向顺序,依次执行Wrapper、Context、Host、Engine容器的threadStart()方法,由于Wrapper、Context、Host的backgroundProcessorDelay值为-1所以不会执行直至Engine启动。
-
5、Engine的backgroundProcessorDelay值为10,执行Engine的threadStart()方法,通过执行ContainerBackgroundProcessor的方法执行Engine容器本身的线程启动,并且通过container.findChildren()递归调用Host、Context、Wrapper等容器的任务。
public abstract class ContainerBase extends LifecycleMBeanBase implements Container {
protected int backgroundProcessorDelay = -1;
protected synchronized void startInternal() throws LifecycleException {
// Start our subordinate components, if any
Cluster cluster = getClusterInternal();
if (cluster instanceof Lifecycle) {
((Lifecycle) cluster).start();
}
Realm realm = getRealmInternal();
if (realm instanceof Lifecycle) {
((Lifecycle) realm).start();
}
// Start our child containers, if any
Container children[] = findChildren();
List<Future<Void>> results = new ArrayList<>();
for (int i = 0; i < children.length; i++) {
results.add(startStopExecutor.submit(new StartChild(children[i])));
}
MultiThrowable multiThrowable = new MultiThrowable();
for (Future<Void> result : results) {
try {
result.get();
} catch (Throwable e) {
log.error(sm.getString("containerBase.threadedStartFailed"), e);
multiThrowable.add(e);
}
}
// Start the Valves in our pipeline (including the basic), if any
if (pipeline instanceof Lifecycle) {
((Lifecycle) pipeline).start();
}
setState(LifecycleState.STARTING);
// Start our thread
threadStart();
}
周期任务线程启动过程分析
-
1、只有Engine通过new Thread(new ContainerBackgroundProcessor(), threadName)启动后台周期性任务,按照backgroundProcessorDelay的周期性执行。
-
2、ContainerBackgroundProcessor的processChildren方法内部先执行本容器的backgroundProcess()方法,然后在递归调用子容器的processChildren()方法。
-
3、针对容器的container.backgroundProcess()方法继续看细节分析。
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();
}
protected class ContainerBackgroundProcessor implements Runnable {
@Override
public void run() {
Throwable t = null;
try {
while (!threadDone) {
try {
Thread.sleep(backgroundProcessorDelay * 1000L);
} catch (InterruptedException e) {
// Ignore
}
if (!threadDone) {
processChildren(ContainerBase.this);
}
}
} catch (RuntimeException|Error e) {
t = e;
throw e;
} finally {
if (!threadDone) {
log.error(unexpectedDeathMessage, t);
}
}
}
protected void processChildren(Container container) {
ClassLoader originalClassLoader = null;
try {
if (container instanceof Context) {
Loader loader = ((Context) container).getLoader();
// Loader will be null for FailedContext instances
if (loader == null) {
return;
}
// Ensure background processing for Contexts and Wrappers
// is performed under the web app's class loader
originalClassLoader = ((Context) container).bind(false, null);
}
container.backgroundProcess();
Container[] children = container.findChildren();
for (int i = 0; i < children.length; i++) {
if (children[i].getBackgroundProcessorDelay() <= 0) {
processChildren(children[i]);
}
}
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
log.error("Exception invoking periodic operation: ", t);
} finally {
if (container instanceof Context) {
((Context) container).unbind(false, originalClassLoader);
}
}
}
}
}
容器后台线程处理过程
-
1、cluster.backgroundProcess()执行Cluster的后台处理。
-
2、realm.backgroundProcess()执行Realm的后台处理。
-
3、pipeline的backgroundProcess()执行valve链的后台处理。
-
4、fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null)的执行容器的周期性任务。
public abstract class ContainerBase extends LifecycleMBeanBase
implements Container {
public void backgroundProcess() {
if (!getState().isAvailable())
return;
Cluster cluster = getClusterInternal();
if (cluster != null) {
try {
cluster.backgroundProcess();
} catch (Exception e) {
log.warn(sm.getString("containerBase.backgroundProcess.cluster",
cluster), e);
}
}
Realm realm = getRealmInternal();
if (realm != null) {
try {
realm.backgroundProcess();
} catch (Exception e) {
log.warn(sm.getString("containerBase.backgroundProcess.realm", realm), e);
}
}
Valve current = pipeline.getFirst();
while (current != null) {
try {
current.backgroundProcess();
} catch (Exception e) {
log.warn(sm.getString("containerBase.backgroundProcess.valve", current), e);
}
current = current.getNext();
}
// 启动周期性任务
fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null);
}
}
StandardContext容器重写backgroundProcess方法
-
StandardContext继承ContainerBase并覆写backgroundProcess()方法。
-
StandardContext执行loader.backgroundProcess()方法。
-
StandardContext执行manager.backgroundProcess()方法。
-
StandardContext执行resources.backgroundProcess()方法。
-
StandardContext执行((DefaultInstanceManager)).backgroundProcess()方法。
-
StandardContext执行super.backgroundProcess()父类的backgroundProcess()方法。
public class StandardContext extends ContainerBase
implements Context, NotificationEmitter {
public void backgroundProcess() {
if (!getState().isAvailable())
return;
Loader loader = getLoader();
if (loader != null) {
try {
loader.backgroundProcess();
} catch (Exception e) {
log.warn(sm.getString(
"standardContext.backgroundProcess.loader", loader), e);
}
}
Manager manager = getManager();
if (manager != null) {
try {
manager.backgroundProcess();
} catch (Exception e) {
log.warn(sm.getString(
"standardContext.backgroundProcess.manager", manager),
e);
}
}
WebResourceRoot resources = getResources();
if (resources != null) {
try {
resources.backgroundProcess();
} catch (Exception e) {
log.warn(sm.getString(
"standardContext.backgroundProcess.resources",
resources), e);
}
}
InstanceManager instanceManager = getInstanceManager();
if (instanceManager instanceof DefaultInstanceManager) {
try {
((DefaultInstanceManager)instanceManager).backgroundProcess();
} catch (Exception e) {
log.warn(sm.getString(
"standardContext.backgroundProcess.instanceManager",
resources), e);
}
}
super.backgroundProcess();
}
}
StandardWrapper容器重写backgroundProcess方法
-
StandardWrapper继承ContainerBase并覆写backgroundProcess()方法。
-
StandardWrapper执行super.backgroundProcess()父类的backgroundProcess()方法。
-
StandardWrapper执行((PeriodicEventListener) getServlet()).periodicEvent()的方法。
public class StandardWrapper extends ContainerBase
implements ServletConfig, Wrapper, NotificationEmitter {
public void backgroundProcess() {
super.backgroundProcess();
if (!getState().isAvailable())
return;
if (getServlet() instanceof PeriodicEventListener) {
((PeriodicEventListener) getServlet()).periodicEvent();
}
}
}
网友评论