来源
本文整理自 <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);
}