前言
上篇文章分析了Service的 init 和 start 方法,在这两个方法中关键的是调用 Engine 和 Connector 的 init 和 start 方法,一个 Service 里只有一个 Engine,有多个 Connector。本篇文章分析 Engine 的启动。Engine 的实现类是 StandardEngine,java
1 StandardEngine#init 方法 web
StandardEngine 的父类是 ContainerBase ,而 ContainerBase 的父类是 LifecycleMBeanBase。ContainerBase 和 StandardEngine 都实现了 initInternal 和 startInternal 方法。
1.1 StandardEngine#initInternal 方法 apache
@Override protected void initInternal() throws LifecycleException { // Ensure that a Realm is present before any attempt is made to start // one. This will create the default NullRealm if necessary. getRealm(); super.initInternal(); }
StandardEngine 的 initInternal 方法中,先调用了 getRealm() 方法,确保 StandardEngine 的父类 StandardEngine中的 Realm 类型的属性不为空。
Realm 是 Tomcat 的特性功能,跟 NamingResouce,这里先略过。
而后调用了 super.initInternal(),也就是 ContainerBase 的 initInternal 方法segmentfault
1.2 ContainerBase#initInternal 方法 tomcat
@Override protected void initInternal() throws LifecycleException { reconfigureStartStopExecutor(getStartStopThreads()); super.initInternal(); } /** * The number of threads available to process start and stop events for any * children associated with this container. */ private int startStopThreads = 1; protected ExecutorService startStopExecutor; @Override public int getStartStopThreads() { return startStopThreads; } private void reconfigureStartStopExecutor(int threads) { if (threads == 1) { // Use a fake executor if (!(startStopExecutor instanceof InlineExecutorService)) { startStopExecutor = new InlineExecutorService(); } } else { // Delegate utility execution to the Service Server server = Container.getService(this).getServer(); server.setUtilityThreads(threads); startStopExecutor = server.getUtilityExecutor(); } }
super.initInternal() 是调用的 LifecycleMBeanBase 的 initInternal() 方法。以前的文章里讲过了,这里就略过。
reconfigureStartStopExecutor 方法是设置一个线程池来处理子容器启动和关闭事件,。
能够看出,getStartStopThreads() 返回的是成员变量 startStopThreads,而 startStopThreads 默认为 1 ,因此 reconfigureStartStopExecutor 方法会走 if 语句,而 startStopExecutor 最开始是没有赋值的,startStopExecutor instanceof InlineExecutorService 会返回 false,所以最终会执行 startStopExecutor = new InlineExecutorService(),InlineExecutorService 只是简单地实现了 java.util.concurrent.AbstractExecutorService 类。
最终 reconfigureStartStopExecutor 给 startStopExecutor 这个成员变量设置了,startStopExecutor。session
2 StandardEngine#start 方法 app
StandardEngine 的 start 方法跟它的 init 方法相似。
2.1 StandardEngine#startInternal 方法 异步
/** * Start this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void startInternal() throws LifecycleException { // Log our server identification information if (log.isInfoEnabled()) { log.info(sm.getString("standardEngine.start", ServerInfo.getServerInfo())); } // Standard container startup super.startInternal(); }
StandardEngine#startInternal 方法只是简单地调用了 ContainerBase 的startInternal 方法。ide
2.2 ContainerBase#startInternal 方法 ui
/** * Start this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void startInternal() throws LifecycleException { // Start our subordinate components, if any logger = null; getLogger(); 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 = null; for (Future<Void> result : results) { try { result.get(); } catch (Throwable e) { log.error(sm.getString("containerBase.threadedStartFailed"), e); if (multiThrowable == null) { multiThrowable = new MultiThrowable(); } multiThrowable.add(e); } } if (multiThrowable != null) { throw new LifecycleException(sm.getString("containerBase.threadedStartFailed"), multiThrowable.getThrowable()); } // Start the Valves in our pipeline (including the basic), if any if (pipeline instanceof Lifecycle) { ((Lifecycle) pipeline).start(); } setState(LifecycleState.STARTING); // Start our thread if (backgroundProcessorDelay > 0) { monitorFuture = Container.getService(ContainerBase.this).getServer() .getUtilityExecutor().scheduleWithFixedDelay( new ContainerBackgroundProcessorMonitor(), 0, 60, TimeUnit.SECONDS); } }
首先调用了 getClusterInternal() 和 getRealmInternal() 方法分别获取了,Cluster 和 Realm 对象,而后调用这两个对象的 start 方法啊,若是这两个对象是继承自 Lifecycle 的话。
Cluster 和 Realm 是 tomcat 新增的特性,这里就先略过不讲。
其次,用 findChildren() 方法获取子容器
并将子容器的启动封装在一个 StartChild 对象里,
而后将这个 StartChild 对象丢到 startStopExecutor 中,这个 startStopExecutor 就是在文中上面介绍到的,
并等待执行结果,若是执行中出现异常,则将收集到 MultiThrowable 对象了,并抛出 LifecycleException 异常。
private static class StartChild implements Callable<Void> { private Container child; public StartChild(Container child) { this.child = child; } @Override public Void call() throws LifecycleException { child.start(); return null; } }
StartChild 类就只是简单执行 Container 对象的 start 方法。
Engine 的子容器是 Host,而 Host 的子容器是 Context,Context 的子容器是 Wrapper。
因此 Host#start,Context#start,Wrapper#start 会被依次调用。
Host#start,Context#start,Wrapper#start 会在后面的文章中介绍,这里先略过。
调用完子容器的 start 方法以后,就开始调用 Pipeline 的 start 方法。
Pipeline 是 Container 用来处理请求的,上篇文章提到 Container 是处理请求的,Container 处理请求其实是交给 Pipeline 处理的,Pipeline 串联了一个或多个 Valve,用 Value 去处理请求。
Pipeline 和 Valve 是处理Http请求很是重要的组件,后面的文章会专门讲解。
最后,根据 backgroundProcessorDelay 判断是否须要在后台处理一些任务,若是须要就使用 Server 里的 utilityExecutorWrapper 线程池去执行 ContainerBackgroundProcessorMonitor 任务。utilityExecutorWrapper 在这篇文章中介绍过。
backgroundProcessorDelay 的默认值是 -1,可是在 StandardEngine 里被赋值为 10。
protected class ContainerBackgroundProcessorMonitor implements Runnable { @Override public void run() { if (getState().isAvailable()) { threadStart(); } } }
ContainerBackgroundProcessorMonitor 任务很简单,就是执行 threadStart() 方法。
2.3 ContainerBase#threadStart() 方法
/** * Start the background thread that will periodically check for * session timeouts. */ protected void threadStart() { if (backgroundProcessorDelay > 0 && (getState().isAvailable() || LifecycleState.STARTING_PREP.equals(getState())) && (backgroundProcessorFuture == null || backgroundProcessorFuture.isDone())) { if (backgroundProcessorFuture != null && backgroundProcessorFuture.isDone()) { // There was an error executing the scheduled task, get it and log it try { backgroundProcessorFuture.get(); } catch (InterruptedException | ExecutionException e) { log.error(sm.getString("containerBase.backgroundProcess.error"), e); } } backgroundProcessorFuture = Container.getService(this).getServer().getUtilityExecutor() .scheduleWithFixedDelay(new ContainerBackgroundProcessor(), backgroundProcessorDelay, backgroundProcessorDelay, TimeUnit.SECONDS); } }
threadStart() 的重点是使用 Server 里的 utilityExecutorWrapper 去执行 ContainerBackgroundProcessor 任务。
2.4 ContainerBackgroundProcessor的 run 方法
/** * Private runnable class to invoke the backgroundProcess method * of this container and its children after a fixed delay. */ protected class ContainerBackgroundProcessor implements Runnable { @Override public void run() { processChildren(ContainerBase.this); } 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(sm.getString("containerBase.backgroundProcess.error"), t); } finally { if (container instanceof Context) { ((Context) container).unbind(false, originalClassLoader); } } } }
ContainerBackgroundProcessor 的一个重点是调用 Container 的 backgroundProcess() 方法,而后递归处理调用 ContainerBackgroundProcessor#processChildren 来调用子容器的 backgroundProcess(),另外,若是 Container 是 Context 的实现来的话,还会调用 Context#bind 方法。
StandardEngine 没有重载 ContainerBase 的 backgroundProcess() 方法,而 StandardHost、StandardContext、StandardWrapper 都没有从新给 backgroundProcessorDelay 赋值,因此这些类的 getBackgroundProcessorDelay() 返回的值是 -1,所以都这些类的 backgroundProcess() 都将会执行。
2.5 ContainerBase#backgroundProcess() 方法
/** * Execute a periodic task, such as reloading, etc. This method will be * invoked inside the classloading context of this container. Unexpected * throwables will be caught and logged. */ @Override 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); }
能够看出 ContainerBase 的 backgroundProcess() 方法依次调用 Cluster、Realm、Valve 的 backgroundProcess() 方法,而后触发一个 Lifecycle.PERIODIC_EVENT 事件。
Cluster、Realm、Valve 不是本文的重点,这里就不细讲了。
小结本文介绍了 Engine 的 initInternal 和 startInternal 方法。在这两个方法里 StandardEngine 主要作的事情就是调用父类 ContainerBase 的重载方法,在 ContainerBase 的 startInternal 方法里,依次调用了 Container 里有的 Cluster 对象、Realm对象、子Container对象、Pipeline对象的 start 方法,而且异步调用了 Container 自身的 backgroundProcess 方法,以及递归调用了子类的 backgroundProcess 方法。