來源
本文整理自 <Tomcat內核設計剖析>、<Tomcat結構解析> 加上自己的理解、源碼來自 Tomcat8.5 版本
Tomcat啟動流程分析
Init流程時序圖
Start流程時序圖
Bootstrap
// org.apache.catalina.startup.Bootstrap
public static void main(String args[]) {
if (daemon == null) {
// 先創建一個 bootstrap 實例
Bootstrap bootstrap = new Bootstrap();
try {
bootstrap.init();
} catch (Throwable t) {
return;
}
daemon = bootstrap;
} else {
Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
}
try {
// 默認執行 start 方法
String command = "start";
if (args.length > 0) {
command = args[args.length - 1];
}
if (command.equals("startd")) {
args[args.length - 1] = "start";
daemon.load(args);
daemon.start();
} else if (command.equals("stopd")) {
args[args.length - 1] = "stop";
daemon.stop();
} else if (command.equals("start")) {
// 是否讓主線程不退出
daemon.setAwait(true);
// 反射調用 catalinaDaemon#load 方法,根據server.xml 創建服務
daemon.load(args);
// 反射調用 catalinaDaemon#start 方法,啟動服務
daemon.start();
} else if (command.equals("stop")) {
daemon.stopServer(args);
} else if (command.equals("configtest")) {
daemon.load(args);
if (null==daemon.getServer()) {
System.exit(1);
}
System.exit(0);
}
}
}
/**
* Initialize daemon.
* @throws Exception Fatal initialization error
*/
public void init() throws Exception {
// 初始化類加載器
initClassLoaders();
Thread.currentThread().setContextClassLoader(catalinaLoader);
SecurityClassLoad.securityClassLoad(catalinaLoader);
Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
// 反射生成 Catalina 類
Object startupInstance = startupClass.getConstructor().newInstance();
String methodName = "setParentClassLoader";
Class<?> paramTypes[] = new Class[1];
paramTypes[0] = Class.forName("java.lang.ClassLoader");
Object paramValues[] = new Object[1];
paramValues[0] = sharedLoader;
// 反射調用 Catalina 類的 setParentClassLoader 方法。
Method method =
startupInstance.getClass().getMethod(methodName, paramTypes);
method.invoke(startupInstance, paramValues);
catalinaDaemon = startupInstance;
}
private void initClassLoaders() {
try {
commonLoader = createClassLoader("common", null);
if( commonLoader == null ) {
commonLoader=this.getClass().getClassLoader();
}
catalinaLoader = createClassLoader("server", commonLoader);
sharedLoader = createClassLoader("shared", commonLoader);
} catch (Throwable t) {
System.exit(1);
}
}
流程圖
Catalina
// org.apache.catalina.startup.Catalina
// 設置 await值,會在start方法中服務器啟動完成后來判斷是否進入等待狀態
// true :后續會去監聽8005端口
// false:運行完成后就退出
public void setAwait(boolean b) {
await = b;
}
public void load() {
// 已經加載就返回
if (loaded) { return; }
// 設置加載狀態
loaded = true;
// 在解析之前,設置一些系統屬性
initNaming();
// 通過 digester 解析 server.xml 配置文件
Digester digester = createStartDigester();
InputSource inputSource = null;
InputStream inputStream = null;
File file = null;
try {
try {
// 默認指定了 conf/server.xml
file = configFile();
inputStream = new FileInputStream(file);
inputSource = new InputSource(file.toURI().toURL().toString());
}
if (inputStream == null) {
try {
inputStream = getClass().getClassLoader()
.getResourceAsStream(getConfigFile());
inputSource = new InputSource
(getClass().getClassLoader()
.getResource(getConfigFile()).toString());
}
}
if (inputStream == null) {
// 嘗試加載 server-embed.xml
try {
inputStream = getClass().getClassLoader()
.getResourceAsStream("server-embed.xml");
inputSource = new InputSource
(getClass().getClassLoader()
.getResource("server-embed.xml").toString());
}
}
// 依舊找不到文件,返回
if (inputStream == null || inputSource == null) {
return;
}
try {
inputSource.setByteStream(inputStream);
digester.push(this);
// 解析 xml
digester.parse(inputSource);
}
}
getServer().setCatalina(this);
// 在 static中定義,
getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());
// Replace System.out and System.err with a custom PrintStream
initStreams();
// 創建 Server
getServer().init();
}
/*
Digester 查相關資料:Java解析xml主要由DOM4J(一次讀取到內存並解析)、SAX(一次解析一部分),digester本身采用SAX的解析方式,並提供了一層包裝,對使用者更加友好,后來獨立出來成為apache的Commons下面的[一個單獨的子項目](http://commons.apache.org/proper/commons-digester/)。
*/
public void start() {
if (getServer() == null) {
load();
}
if (getServer() == null) {
return;
}
try {
// 調用Server的start方法啟動服務器
getServer().start();
} catch (LifecycleException e) {
getServer().destroy();
return;
}
// 注冊 關閉 鈎子方法
if (useShutdownHook) {
if (shutdownHook == null) {
shutdownHook = new CatalinaShutdownHook();
}
Runtime.getRuntime().addShutdownHook(shutdownHook);
LogManager logManager = LogManager.getLogManager();
if (logManager instanceof ClassLoaderLogManager) {
((ClassLoaderLogManager) logManager).setUseShutdownHook(
false);
}
}
// 此處判斷 主線程是否await
if (await) {
// 在 StandardServer 中調用,用來監聽 8005 端口,
// 收到 SHUTDOWN 命令關閉 Server
await();
stop();
}
}
Init流程圖
Start流程圖
StandardServer
@Override
protected void initInternal() throws LifecycleException {
super.initInternal();
// 注冊全局 String cache
onameStringCache = register(new StringCache(), "type=StringCache");
// 注冊 MBeanFactory
MBeanFactory factory = new MBeanFactory();
factory.setContainer(this);
onameMBeanFactory = register(factory, "type=MBeanFactory");
// 注冊命名資源
globalNamingResources.init();
// Populate the extension validator with JARs from common and shared
// class loaders
if (getCatalina() != null) {
ClassLoader cl = getCatalina().getParentClassLoader();
while (cl != null && cl != ClassLoader.getSystemClassLoader()) {
if (cl instanceof URLClassLoader) {
URL[] urls = ((URLClassLoader) cl).getURLs();
for (URL url : urls) {
if (url.getProtocol().equals("file")) {
File f = new File (url.toURI());
if (f.isFile() &&
f.getName().endsWith(".jar")) {
ExtensionValidator.addSystemResource(f);
}
}
}
}
cl = cl.getParent();
}
}
// 初始化定義的所有 Service
for (int i = 0; i < services.length; i++) {
services[i].init();
}
}
@Override
protected void startInternal() throws LifecycleException {
// 設置狀態
fireLifecycleEvent(CONFIGURE_START_EVENT, null);
// 觸發事件
setState(LifecycleState.STARTING);
globalNamingResources.start();
synchronized (servicesLock) {
for (int i = 0; i < services.length; i++) {
services[i].start();
}
}
}
@Override
public void await() {
try {
// port 默認 8005
awaitSocket = new ServerSocket(port, 1,
InetAddress.getByName(address));
} catch (IOException e) {
return;
}
// 匹配 SHUTDOWN 命令,用來關閉服務器
boolean match = command.toString().equals(shutdown);
if (match) {
break;
}
ServerSocket serverSocket = awaitSocket;
awaitThread = null;
awaitSocket = null;
// 關閉Server socket並返回
if (serverSocket != null) {
serverSocket.close();
}
}
StandardService
@Override
protected void initInternal() throws LifecycleException {
super.initInternal();
// Engine初始化,一個Service對應一個Engine
if (engine != null) {
engine.init();
}
// 初始化Executor,默認 不會執行
for (Executor executor : findExecutors()) {
if (executor instanceof JmxEnabled) {
((JmxEnabled) executor).setDomain(getDomain());
}
executor.init();
}
// 初始化 MapperListener , 默認 LifecycleMBeanBase.java
mapperListener.init();
// 初始化 Connector,server.xml 配置的 Connector
synchronized (connectorsLock) {
for (Connector connector : connectors) {
connector.init();
}
}
}
@Override
protected void startInternal() throws LifecycleException {
setState(LifecycleState.STARTING);
if (engine != null) {
synchronized (engine) {
engine.start();
}
}
synchronized (executors) {
for (Executor executor: executors) {
executor.start();
}
}
mapperListener.start();
synchronized (connectorsLock) {
for (Connector connector: connectors) {
if (connector.getState() != LifecycleState.FAILED) {
connector.start();
}
}
}
}
ContainerBase
是容器的抽象父類,定義了容器生命周期中公共方法。Engine、Host、Context、Wrapper繼承此父類。
@Override
protected void initInternal() throws LifecycleException {
// 創建 線程池
BlockingQueue<Runnable> startStopQueue = new LinkedBlockingQueue<>();
startStopExecutor = new ThreadPoolExecutor(
getStartStopThreadsInternal(),
getStartStopThreadsInternal(), 10, TimeUnit.SECONDS,
startStopQueue,
new StartStopThreadFactory(getName() + "-startStop-"));
startStopExecutor.allowCoreThreadTimeOut(true);
super.initInternal();
}
@Override
protected synchronized void startInternal() throws LifecycleException {
// 如果有 Cluster和 Realm則調用其 start 方法
Cluster cluster = getClusterInternal();
if (cluster instanceof Lifecycle) {
((Lifecycle) cluster).start();
}
Realm realm = getRealmInternal();
if (realm instanceof Lifecycle) {
((Lifecycle) realm).start();
}
// 通過 Future 調用所有子容器的 start方法
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])));
}
boolean fail = false;
for (Future<Void> result : results) {
try {
// 獲取子容器 start 方法結果
result.get();
} catch (Exception e) {
log.error(sm.getString("containerBase.threadedStartFailed"), e);
fail = true;
}
}
if (fail) {
throw new LifecycleException(
sm.getString("containerBase.threadedStartFailed"));
}
// 啟用管道,后面介紹到
if (pipeline instanceof Lifecycle)
((Lifecycle) pipeline).start();
// 設置狀態值
setState(LifecycleState.STARTING);
// 啟動后台線程,日志輸出等工作,
threadStart();
}
// 開啟后台線程,定時檢查 session 超時、
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, 默認 10s一次
// 在 StandardEngine 構造函數中定義
protected void processChildren(Container ContainerBase.this) {
container.backgroundProcess();
Container[] children = container.findChildren();
for (int i = 0; i < children.length; i++) {
if (children[i].getBackgroundProcessorDelay() <= 0) {
processChildren(children[i]);
}
}
}
@Override
public void backgroundProcess() {
if (!getState().isAvailable())
return;
Cluster cluster = getClusterInternal();
if (cluster != null) {
cluster.backgroundProcess();
}
Realm realm = getRealmInternal();
if (realm != null) {
realm.backgroundProcess();
}
Valve current = pipeline.getFirst();
while (current != null) {
current.backgroundProcess();
current = current.getNext();
}
fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null);
}
// LifecycleBase
protected void fireLifecycleEvent(String type, Object data) {
LifecycleEvent event = new LifecycleEvent(this, type, data);
for (LifecycleListener listener : lifecycleListeners) {
listener.lifecycleEvent(event);
}
}
// 看一下 HostConfig 的 lifecycleEvent 方法
@Override
public void lifecycleEvent(LifecycleEvent event) {
if (event.getType().equals(Lifecycle.PERIODIC_EVENT)) {
// 是否自動部署
check();
} else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {
beforeStart();
} else if (event.getType().equals(Lifecycle.START_EVENT)) {
start();
} else if (event.getType().equals(Lifecycle.STOP_EVENT)) {
stop();
}
}
容器的作用
Container的4個容器是逐層包含的關系。它們之間的關系如下圖:
1、Engine:用來管理多個站點,一個Service最多只能有一個Engine。
2、Host:代表一個站點,通過配置Host可以添加站點。
3、Context:代表一個應用程序,對應一個WEB-INF目錄。
4、Wrapper:每個Wrapper封裝一個Servlet。
容器的配置
1、
<Server port="8005" shutdown="SHUTDOWN">
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<!-- Define an AJP 1.3 Connector on port 8009 -->
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
<Engine name="Catalina" defaultHost="localhost">
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
</Host>
</Engine>
</Service>
</Server>
- Server 在 8005端口監聽關閉命令“SHUTDOWN”;
- Server 中定義了一個 Catalina的Service;
- Service 中定義了兩個Connector:
- 一個是HTTP協議;
- 一個是AJP協議(用於集成);
- Service 中還定義了了一個Catalina的Engine;
- Engine 中定義了 localhost 的 Host;
- defaultHost:請求的域名如果在所有的Host的name和Alias中都找不到使用的默認值
- Host:
- name:表示域名;
- appBase:站點的位置;
- unpackWARS:是否自動解壓war包;
- autoDeploy:是否自動部署;
- 子標簽:
excelib.com :給localhost定義別名;
2、Context通過文件配置的方式一共有5個位置可以配置:
- conf/server.xml中的Context標簽;
- conf/[enginename]/[hostname]/目錄下以應用命名的 xml 文件。
- 應用自己的 /META-INT/context.xml;
- conf/context.xml 文件
- conf/[enginename]/[hostname]/context.xml.default文件;
3、前三個用於配置單獨的應用,后面2種是Context共享的。第4種是 整個 Tomcat 共享,第5種配置的內容在對應的站點(Host)中共享。第1種方式只有在Tomcat重啟才會重新加載,不推薦使用。
<!--
用於全局配置
The contents of this file will be loaded for each web application
-->
<Context>
<!-- Default set of monitored resources. If one of these changes, the -->
<!-- web application will be reloaded. -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
</Context>
4、Wrapper的配置,在web.xml中配置的Servlet,一個Servlet對應一個Wrapper、可以在 conf/web.xml 中配置全局的 Wrapper,處理 Jsp的 JspServlet的配置等。
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>fork</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>xpoweredBy</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
<url-pattern>*.jspx</url-pattern>
</servlet-mapping>
<!--配置了 session 超時時間-->
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<!-- 很多 mime 類型 -->
<mime-mapping>
</mime-mapping>
StandardEngine
public StandardEngine() {
super();
// pipeline 設置 basicValve
pipeline.setBasic(new StandardEngineValve());
setJvmRoute(System.getProperty("jvmRoute"));
// 設置等待時間 10
backgroundProcessorDelay = 10;
}
@Override
protected void initInternal() throws LifecycleException {
// 沒有定義 Realm ,設置一個 NullRealm,權限訪問。
getRealm();
super.initInternal();
}
@Override
protected synchronized void startInternal() throws LifecycleException {
super.startInternal();
}
StandardHost
public StandardHost() {
super();
// 設置 BasicValve
pipeline.setBasic(new StandardHostValve());
}
@Override
protected synchronized void startInternal() throws LifecycleException {
// 設置 error Valve
String errorValve = getErrorReportValveClass();
if ((errorValve != null) && (!errorValve.equals(""))) {
try {
boolean found = false;
Valve[] valves = getPipeline().getValves();
for (Valve valve : valves) {
if (errorValve.equals(valve.getClass().getName())) {
found = true;
break;
}
}
if(!found) {
// 綁定 errorValve
Valve valve =
(Valve) Class.forName(errorValve).getConstructor().newInstance();
getPipeline().addValve(valve);
}
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
}
}
super.startInternal();
}
StandardContext
public StandardContext() {
super();
// 設置 BasicValve
pipeline.setBasic(new StandardContextValve());
// 廣播通知
broadcaster = new NotificationBroadcasterSupport();
if (!Globals.STRICT_SERVLET_COMPLIANCE) {
resourceOnlyServlets.add("jsp");
}
}
@Override
protected synchronized void startInternal() throws LifecycleException {
// Send j2ee.state.starting notification
if (this.getObjectName() != null) {
Notification notification = new Notification("j2ee.state.starting",
this.getObjectName(), sequenceNumber.getAndIncrement());
broadcaster.sendNotification(notification);
}
setConfigured(false);
boolean ok = true;
// namingResources 啟動
if (namingResources != null) {
namingResources.start();
}
// Post work directory
postWorkDirectory();
// Add missing components as necessary
if (getResources() == null) { // (1) Required by Loader
try {
setResources(new StandardRoot(this));
} catch (IllegalArgumentException e) {
ok = false;
}
}
if (ok) {
// 加載 /WEB-INF/classes/META-INF/resources 目錄下資源
resourcesStart();
}
// 設置加載器
if (getLoader() == null) {
WebappLoader webappLoader = new WebappLoader(getParentClassLoader());
webappLoader.setDelegate(getDelegate());
setLoader(webappLoader);
}
// cookie 處理器
if (cookieProcessor == null) {
cookieProcessor = new Rfc6265CookieProcessor();
}
// 初始化 CharsetMapper
getCharsetMapper();
// 驗證 /META-INF/MANIFEST.MF
boolean dependencyCheck = true;
try {
dependencyCheck = ExtensionValidator.validateApplication
(getResources(), this);
} catch (IOException ioe) {
dependencyCheck = false;
}
// // 驗證失敗, application 不可用
if (!dependencyCheck) {
ok = false;
}
// catalina.useNaming 環境變量
String useNamingProperty = System.getProperty("catalina.useNaming");
if ((useNamingProperty != null)
&& (useNamingProperty.equals("false"))) {
useNaming = false;
}
if (ok && isUseNaming()) {
if (getNamingContextListener() == null) {
NamingContextListener ncl = new NamingContextListener();
ncl.setName(getNamingContextName());
ncl.setExceptionOnFailedWrite(getJndiExceptionOnFailedWrite());
// 注冊 LifecycleListener
addLifecycleListener(ncl);
setNamingContextListener(ncl);
}
}
// Binding thread
ClassLoader oldCCL = bindThread();
try {
if (ok) {
// Start our subordinate components, if any
Loader loader = getLoader();
if (loader instanceof Lifecycle) {
((Lifecycle) loader).start();
}
// since the loader just started, the webapp classloader is now
// created.
setClassLoaderProperty("clearReferencesRmiTargets",
getClearReferencesRmiTargets());
setClassLoaderProperty("clearReferencesStopThreads",
getClearReferencesStopThreads());
setClassLoaderProperty("clearReferencesStopTimerThreads",
getClearReferencesStopTimerThreads());
setClassLoaderProperty("clearReferencesHttpClientKeepAliveThread",
getClearReferencesHttpClientKeepAliveThread());
setClassLoaderProperty("clearReferencesObjectStreamClassCaches",
getClearReferencesObjectStreamClassCaches());
// By calling unbindThread and bindThread in a row, we setup the
// current Thread CCL to be the webapp classloader
unbindThread(oldCCL);
oldCCL = bindThread();
// Initialize logger again. Other components might have used it
// too early, so it should be reset.
logger = null;
getLogger();
Realm realm = getRealmInternal();
if(null != realm) {
if (realm instanceof Lifecycle) {
((Lifecycle) realm).start();
}
// Place the CredentialHandler into the ServletContext so
// applications can have access to it. Wrap it in a "safe"
// handler so application's can't modify it.
CredentialHandler safeHandler = new CredentialHandler() {
@Override
public boolean matches(String inputCredentials, String storedCredentials) {
return getRealmInternal().getCredentialHandler().matches(inputCredentials, storedCredentials);
}
@Override
public String mutate(String inputCredentials) {
return getRealmInternal().getCredentialHandler().mutate(inputCredentials);
}
};
context.setAttribute(Globals.CREDENTIAL_HANDLER, safeHandler);
}
// 調用事件
fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null);
// 在不可用的時候,啟動子容器
for (Container child : findChildren()) {
if (!child.getState().isAvailable()) {
child.start();
}
}
// pipeline 的啟動
if (pipeline instanceof Lifecycle) {
((Lifecycle) pipeline).start();
}
// 獲取集群管理器
Manager contextManager = null;
Manager manager = getManager();
if (manager == null) {
if ( (getCluster() != null) && distributable) {
try {
contextManager = getCluster().createManager(getName());
} catch (Exception ex) {
ok = false;
}
} else {
contextManager = new StandardManager();
}
}
// 配置默認管理器
if (contextManager != null) {
setManager(contextManager);
}
// 注冊管理器
if (manager!=null && (getCluster() != null) && distributable) {
getCluster().registerManager(manager);
}
}
if (!getConfigured()) {
ok = false;
}
// 將資源 放到 servlet Context 中
if (ok)
getServletContext().setAttribute
(Globals.RESOURCES_ATTR, getResources());
if (ok ) {
if (getInstanceManager() == null) {
javax.naming.Context context = null;
if (isUseNaming() && getNamingContextListener() != null) {
context = getNamingContextListener().getEnvContext();
}
Map<String, Map<String, String>> injectionMap = buildInjectionMap(
getIgnoreAnnotations() ? new NamingResourcesImpl(): getNamingResources());
setInstanceManager(new DefaultInstanceManager(context,
injectionMap, this, this.getClass().getClassLoader()));
}
getServletContext().setAttribute(
InstanceManager.class.getName(), getInstanceManager());
InstanceManagerBindings.bind(getLoader().getClassLoader(), getInstanceManager());
}
// Create context attributes that will be required
if (ok) {
getServletContext().setAttribute(
JarScanner.class.getName(), getJarScanner());
}
// 設置上下文 init 參數
mergeParameters();
// Call ServletContainerInitializers
for (Map.Entry<ServletContainerInitializer, Set<Class<?>>> entry :
initializers.entrySet()) {
try {
entry.getKey().onStartup(entry.getValue(),
getServletContext());
} catch (ServletException e) {
log.error(sm.getString("standardContext.sciFail"), e);
ok = false;
break;
}
}
// 調用 listener
if (ok) {
if (!listenerStart()) {
ok = false;
}
}
// Check constraints for uncovered HTTP methods
// Needs to be after SCIs and listeners as they may programmatically
// change constraints
if (ok) {
checkConstraintsForUncoveredMethods(findConstraints());
}
try {
// Start manager
Manager manager = getManager();
if (manager instanceof Lifecycle) {
((Lifecycle) manager).start();
}
} catch(Exception e) {
ok = false;
}
// filter調用
if (ok) {
if (!filterStart()) {
ok = false;
}
}
// 初始化 Servlet,如果配置了 LoadOnStartUp
if (ok) {
if (!loadOnStartup(findChildren())){
ok = false;
}
}
// 啟動后台線程
super.threadStart();
} finally {
unbindThread(oldCCL);
}
// 資源回收
getResources().gc();
if (!ok) {
setState(LifecycleState.FAILED);
} else {
setState(LifecycleState.STARTING);
}
}
StandardWrapper
public StandardWrapper() {
super();
swValve = new StandardWrapperValve();
// 設置 BasicValve
pipeline.setBasic(swValve);
broadcaster = new NotificationBroadcasterSupport();
}
@Override
protected synchronized void startInternal() throws LifecycleException {
// Send j2ee.state.starting notification
if (this.getObjectName() != null) {
Notification notification = new Notification("j2ee.state.starting",
this.getObjectName(),
sequenceNumber++);
broadcaster.sendNotification(notification);
}
super.startInternal();
setAvailable(0L);
// Send j2ee.state.running notification
if (this.getObjectName() != null) {
Notification notification =
new Notification("j2ee.state.running", this.getObjectName(),
sequenceNumber++);
broadcaster.sendNotification(notification);
}
}
StandardPipeline
@Override
protected void initInternal() { }
@Override
protected synchronized void startInternal() throws LifecycleException {
Valve current = first;
if (current == null) {
current = basic;
}
while (current != null) {
if (current instanceof Lifecycle)
((Lifecycle) current).start();
current = current.getNext();
}
setState(LifecycleState.STARTING);
}