tomcat源码研读笔记—tomcat的启动之三 StandardEngine的启动
2018-03-21 17:31
696 查看
这一章节开始,我们进入了所谓的“容器”内部了,standardEngine启动的源码如下:
public void start() throws LifecycleException {
// Log our server identification information
System.out.println(ServerInfo.getServerInfo());
// Standard container startup
super.start();
}
可以知道,standardEngine直接将启动传递给了父类,我们看下standardEngine的继承关系:
1,standardEngine实现了Engine接口,同时继承了ContainerBase
2,ContainerBase实现了Lifecycle,Container和Pipeline接口
根据上边类的继承关系,我们进入ContainerBase内的start方法:
publicsynchronized void start() throws LifecycleException {
// Validate and update our currentcomponent state
if (started)
throw new LifecycleException
(sm.getString("containerBase.alreadyStarted", logName()));
// Notify our interestedLifecycleListeners
lifecycle.fireLifecycleEvent(BEFORE_START_EVENT,null);
addDefaultMapper(this.mapperClass);
started = true;
// Start our subordinate components, ifany
if ((loader != null) && (loaderinstanceof Lifecycle))
((Lifecycle) loader).start();
if ((logger != null) && (loggerinstanceof Lifecycle))
((Lifecycle) logger).start();
if ((manager != null) &&(manager instanceof Lifecycle))
((Lifecycle) manager).start();
if ((cluster != null) &&(cluster instanceof Lifecycle))
((Lifecycle) cluster).start();
if ((realm != null) && (realminstanceof Lifecycle))
((Lifecycle) realm).start();
if ((resources != null) &&(resources instanceof Lifecycle))
((Lifecycle) resources).start();
// Start our Mappers, if any
Mapper mappers[] = findMappers();
for (int i = 0; i < mappers.length;i++) {
if (mappers[i] instanceofLifecycle)
((Lifecycle)mappers[i]).start();
}
// Start our child containers, if any
Container children[] = findChildren();
for (int i = 0; i < children.length;i++) {
if (children[i] instanceofLifecycle)
((Lifecycle)children[i]).start();
}
// Start the Valves in our pipeline(including the basic), if any
if (pipeline instanceof Lifecycle)
((Lifecycle) pipeline).start();
// Notify our interestedLifecycleListeners
lifecycle.fireLifecycleEvent(START_EVENT, null);
// Notify our interestedLifecycleListeners
lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
}
根据源码我们分析如下几点重要的地方:
1, 这里也采用了上边的监听者模式,执行监听者的监听事件,我们根据之前规律,查看Catalina中的Digester机制,从EngineRuleSet中获取到LifeCycleListener的实现类是EngineConfig
2, 从addDefaultMapper方法的参数mapperClass,可以知道StandardEngineMapper被添加到mappers的HashMap集合中
3, 根据Digester机制 获取loader,logger,manager,cluster,realm,resources接口的实现类,并执行对应的start方法,当然这些实现类必须实现了Lifecycle,同时这些属性的对象也不能为空
4, 获取Mappers集合里边的对象,判断是否实现了Lifecycle接口,如实现了,那么执行start方法
5, 根据Digester机制获取子容器children集合,判断子容器是否实现了lifecycle接口,如实现了,那么将执行子容器的start方法
6, 执行管道属性pipeline中的start方法
第一,根据我们之前分析的监听者模式可以知道,最后调用的其实就是实现了LifeCycleListener接口实现类EngineConfig的lifecycleEvent方法,源码如下:
public voidlifecycleEvent(LifecycleEvent event) {
// Identify the engine we areassociated with
try {
engine = (Engine)event.getLifecycle();
if (engine instanceofStandardEngine) {
int engineDebug = ((StandardEngine)engine).getDebug();
if (engineDebug >this.debug)
this.debug = engineDebug;
}
} catch (ClassCastException e) {
log(sm.getString("engineConfig.cce", event.getLifecycle()),e);
return;
}
// Process the event that has occurred
if(event.getType().equals(Lifecycle.START_EVENT))
start();
else if(event.getType().equals(Lifecycle.STOP_EVENT))
stop();
}
这儿方法做了一个判断,判断当前监听事件的被监听者是否是Egine接口的实现类,如果是,那么往下执行,同时判断是否是启动事件,如果是启动事件那么就调用自身的start方法,具体源码:
private voidstart() {
if (debug > 0)
log(sm.getString("engineConfig.start"));
}
只是打印了下记录就什么也没做,监听事件就执行完了。
第二,那么接下来我们查看的是addDefaultMapper方法,因这里讲this.mapperClass作为参数传递到方法体里边了,我从standardEngine的源码上可以知道,这个this.mapperClass,其实就是:StandardEngineMapper
private String mapperClass =
"org.apache.catalina.core.StandardEngineMapper";
而addDefaultMapper的方法体中我们查看源码如下:
protected void addDefaultMapper(StringmapperClass) {
// Do we need a default Mapper?
if (mapperClass == null)
return;
if (mappers.size() >= 1)
return;
// Instantiate and add a default Mapper
try {
Class clazz = Class.forName(mapperClass);
Mapper mapper = (Mapper) clazz.newInstance();
mapper.setProtocol("http");
addMapper(mapper);
} catch (Exception e) {
log(sm.getString("containerBase.addDefaultMapper",mapperClass),
e);
}
}
将StandardEngineMapper加载到内存中,并实例化一个对象,并为对象赋值,如:mapper.setProtocol("http"),然后通过addMapper将这个对象往下传递:
public voidaddMapper(Mapper mapper) {
synchronized(mappers) {
if (mappers.get(mapper.getProtocol())!= null)
throw newIllegalArgumentException("addMapper: Protocol '" +
mapper.getProtocol() +
"' is not unique");
4000
mapper.setContainer((Container)this); // May throw IAE
if (started && (mapperinstanceof Lifecycle)) {
try {
((Lifecycle)mapper).start();
} catch (LifecycleException e){
log("ContainerBase.addMapper: start: ", e);
throw newIllegalStateException
("ContainerBase.addMapper: start: " + e);
}
}
mappers.put(mapper.getProtocol(),mapper);
if (mappers.size() == 1)
this.mapper = mapper;
else
this.mapper = null;
fireContainerEvent(ADD_MAPPER_EVENT, mapper);
}
}
如果mapper的Protocol属性不为空,在之前我们知道,这里设置了为http,所以不为空,那么将为mapper设置容器为当前对象,即为standardEngine; 接下来判断如果mapper实现了lifecycle接口那么将执行start方法,如果没有实现,那么以hashMap的key-value的方式放入mappers对象中,这里是http- StandardEngineMapper
第三点,我们这里暂时不做深入了解,目前只知道有这些操作,等主线分析完了之后,我们再回过头来了解细节
第四点,根据上边的分析,我们知道Mappers里边的StandardEngineMapper并没有实现lifecycle接口,所以,这段代码也跳过
第五点,我们进入findChildren方法里边查看源码:
public Container[] findChildren() {
synchronized (children) {
Container results[] = new Container[children.size()];
return ((Container[]) children.values().toArray(results));
}
}
发现这里其实就是获取children集合的一个hashMap而已,根据编码开闭原则,我们可以知道,这个类里边必定有往这个hashMap增加元素的方法:
private void addChildInternal(Containerchild) {
synchronized(children) {
if (children.get(child.getName()) != null)
throw newIllegalArgumentException("addChild: Child name '" +
child.getName() +
"' is not unique");
child.setParent((Container) this); // May throw IAE
if (started && (child instanceof Lifecycle)) {
try {
((Lifecycle)child).start();
} catch (LifecycleException e){
log("ContainerBase.addChild: start: ", e);
throw newIllegalStateException
("ContainerBase.addChild: start: " + e);
}
}
children.put(child.getName(), child);
fireContainerEvent(ADD_CHILD_EVENT, child);
}
}
我们查看这个方法发现是private修饰的,我们还发现这个内里边还有一个addChild方法调了它:
public voidaddChild(Container child) {
if (System.getSecurityManager() !=null) {
PrivilegedAction dp =
new PrivilegedAddChild(child);
AccessController.doPrivileged(dp);
} else {
addChildInternal(child);
}
}
这个方法是public进行修饰的,但是那个地方调用就了这个方法呢?这个时候,我们又得联想到server.xml的文档结构了,然后再查找Catalina中的代码:
digester.addRuleSet(newHostRuleSet("Server/Service/Engine/"));
然后再查看HostRuleSet中的addRuleInstances源码:
digester.addObjectCreate(prefix+ "Host",
"org.apache.catalina.core.StandardHost",
"className");
digester.addSetProperties(prefix +"Host");
digester.addRule(prefix +"Host",
newCopyParentClassLoaderRule(digester));
digester.addRule(prefix +"Host",
newLifecycleListenerRule
(digester,
"org.apache.catalina.startup.HostConfig",
"hostConfigClass"));
digester.addSetNext(prefix +"Host",
"addChild",
"org.apache.catalina.Container");
这个时候,我们就明白了,原来children里边存着StandardHost对象集合,所以这里有将standardEngine的启动传递给了standardHost对象了
第6点,我们查看pipeline属性代码可以知道:
protectedPipeline pipeline = new StandardPipeline(this);
初始化的时候就讲pipeline赋值了一个StandardPipeline对象,同时将standardEngine作为构造参数传入到对象中,这个地方我们要注意下,在standardEngine的构造方法其实对pipeline进行了一些属性赋值:
public StandardEngine() {
super();
pipeline.setBasic(new StandardEngineValve());
}
我们可以根据digester解析xml的机制,创建standardEngine的时候,就已经为pipeline的basic设置了StandardEngineValve对象,但是根据StandardEngineValve的继承关系,我们只到其实并没有实现lifecycle接口,所以就不执行start方法
分析完了之后,我们来个小综述:
1, standardEngine的start法其实是调用了父类containerBase的start方法
2, containerBase的start方法,利用监听者模式,执行了监听者EngineConfig的监听方法
3, 设置了mappers的值为StandardEngineMapper
利用digester机制,为child增加了standardHost对象,并将standardEngine的start方法传递给了standardHost
standardEngine启动流程图如下:
standardEngine启动关系类图如下:
public void start() throws LifecycleException {
// Log our server identification information
System.out.println(ServerInfo.getServerInfo());
// Standard container startup
super.start();
}
可以知道,standardEngine直接将启动传递给了父类,我们看下standardEngine的继承关系:
1,standardEngine实现了Engine接口,同时继承了ContainerBase
2,ContainerBase实现了Lifecycle,Container和Pipeline接口
根据上边类的继承关系,我们进入ContainerBase内的start方法:
publicsynchronized void start() throws LifecycleException {
// Validate and update our currentcomponent state
if (started)
throw new LifecycleException
(sm.getString("containerBase.alreadyStarted", logName()));
// Notify our interestedLifecycleListeners
lifecycle.fireLifecycleEvent(BEFORE_START_EVENT,null);
addDefaultMapper(this.mapperClass);
started = true;
// Start our subordinate components, ifany
if ((loader != null) && (loaderinstanceof Lifecycle))
((Lifecycle) loader).start();
if ((logger != null) && (loggerinstanceof Lifecycle))
((Lifecycle) logger).start();
if ((manager != null) &&(manager instanceof Lifecycle))
((Lifecycle) manager).start();
if ((cluster != null) &&(cluster instanceof Lifecycle))
((Lifecycle) cluster).start();
if ((realm != null) && (realminstanceof Lifecycle))
((Lifecycle) realm).start();
if ((resources != null) &&(resources instanceof Lifecycle))
((Lifecycle) resources).start();
// Start our Mappers, if any
Mapper mappers[] = findMappers();
for (int i = 0; i < mappers.length;i++) {
if (mappers[i] instanceofLifecycle)
((Lifecycle)mappers[i]).start();
}
// Start our child containers, if any
Container children[] = findChildren();
for (int i = 0; i < children.length;i++) {
if (children[i] instanceofLifecycle)
((Lifecycle)children[i]).start();
}
// Start the Valves in our pipeline(including the basic), if any
if (pipeline instanceof Lifecycle)
((Lifecycle) pipeline).start();
// Notify our interestedLifecycleListeners
lifecycle.fireLifecycleEvent(START_EVENT, null);
// Notify our interestedLifecycleListeners
lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
}
根据源码我们分析如下几点重要的地方:
1, 这里也采用了上边的监听者模式,执行监听者的监听事件,我们根据之前规律,查看Catalina中的Digester机制,从EngineRuleSet中获取到LifeCycleListener的实现类是EngineConfig
2, 从addDefaultMapper方法的参数mapperClass,可以知道StandardEngineMapper被添加到mappers的HashMap集合中
3, 根据Digester机制 获取loader,logger,manager,cluster,realm,resources接口的实现类,并执行对应的start方法,当然这些实现类必须实现了Lifecycle,同时这些属性的对象也不能为空
4, 获取Mappers集合里边的对象,判断是否实现了Lifecycle接口,如实现了,那么执行start方法
5, 根据Digester机制获取子容器children集合,判断子容器是否实现了lifecycle接口,如实现了,那么将执行子容器的start方法
6, 执行管道属性pipeline中的start方法
第一,根据我们之前分析的监听者模式可以知道,最后调用的其实就是实现了LifeCycleListener接口实现类EngineConfig的lifecycleEvent方法,源码如下:
public voidlifecycleEvent(LifecycleEvent event) {
// Identify the engine we areassociated with
try {
engine = (Engine)event.getLifecycle();
if (engine instanceofStandardEngine) {
int engineDebug = ((StandardEngine)engine).getDebug();
if (engineDebug >this.debug)
this.debug = engineDebug;
}
} catch (ClassCastException e) {
log(sm.getString("engineConfig.cce", event.getLifecycle()),e);
return;
}
// Process the event that has occurred
if(event.getType().equals(Lifecycle.START_EVENT))
start();
else if(event.getType().equals(Lifecycle.STOP_EVENT))
stop();
}
这儿方法做了一个判断,判断当前监听事件的被监听者是否是Egine接口的实现类,如果是,那么往下执行,同时判断是否是启动事件,如果是启动事件那么就调用自身的start方法,具体源码:
private voidstart() {
if (debug > 0)
log(sm.getString("engineConfig.start"));
}
只是打印了下记录就什么也没做,监听事件就执行完了。
第二,那么接下来我们查看的是addDefaultMapper方法,因这里讲this.mapperClass作为参数传递到方法体里边了,我从standardEngine的源码上可以知道,这个this.mapperClass,其实就是:StandardEngineMapper
private String mapperClass =
"org.apache.catalina.core.StandardEngineMapper";
而addDefaultMapper的方法体中我们查看源码如下:
protected void addDefaultMapper(StringmapperClass) {
// Do we need a default Mapper?
if (mapperClass == null)
return;
if (mappers.size() >= 1)
return;
// Instantiate and add a default Mapper
try {
Class clazz = Class.forName(mapperClass);
Mapper mapper = (Mapper) clazz.newInstance();
mapper.setProtocol("http");
addMapper(mapper);
} catch (Exception e) {
log(sm.getString("containerBase.addDefaultMapper",mapperClass),
e);
}
}
将StandardEngineMapper加载到内存中,并实例化一个对象,并为对象赋值,如:mapper.setProtocol("http"),然后通过addMapper将这个对象往下传递:
public voidaddMapper(Mapper mapper) {
synchronized(mappers) {
if (mappers.get(mapper.getProtocol())!= null)
throw newIllegalArgumentException("addMapper: Protocol '" +
mapper.getProtocol() +
"' is not unique");
4000
mapper.setContainer((Container)this); // May throw IAE
if (started && (mapperinstanceof Lifecycle)) {
try {
((Lifecycle)mapper).start();
} catch (LifecycleException e){
log("ContainerBase.addMapper: start: ", e);
throw newIllegalStateException
("ContainerBase.addMapper: start: " + e);
}
}
mappers.put(mapper.getProtocol(),mapper);
if (mappers.size() == 1)
this.mapper = mapper;
else
this.mapper = null;
fireContainerEvent(ADD_MAPPER_EVENT, mapper);
}
}
如果mapper的Protocol属性不为空,在之前我们知道,这里设置了为http,所以不为空,那么将为mapper设置容器为当前对象,即为standardEngine; 接下来判断如果mapper实现了lifecycle接口那么将执行start方法,如果没有实现,那么以hashMap的key-value的方式放入mappers对象中,这里是http- StandardEngineMapper
第三点,我们这里暂时不做深入了解,目前只知道有这些操作,等主线分析完了之后,我们再回过头来了解细节
第四点,根据上边的分析,我们知道Mappers里边的StandardEngineMapper并没有实现lifecycle接口,所以,这段代码也跳过
第五点,我们进入findChildren方法里边查看源码:
public Container[] findChildren() {
synchronized (children) {
Container results[] = new Container[children.size()];
return ((Container[]) children.values().toArray(results));
}
}
发现这里其实就是获取children集合的一个hashMap而已,根据编码开闭原则,我们可以知道,这个类里边必定有往这个hashMap增加元素的方法:
private void addChildInternal(Containerchild) {
synchronized(children) {
if (children.get(child.getName()) != null)
throw newIllegalArgumentException("addChild: Child name '" +
child.getName() +
"' is not unique");
child.setParent((Container) this); // May throw IAE
if (started && (child instanceof Lifecycle)) {
try {
((Lifecycle)child).start();
} catch (LifecycleException e){
log("ContainerBase.addChild: start: ", e);
throw newIllegalStateException
("ContainerBase.addChild: start: " + e);
}
}
children.put(child.getName(), child);
fireContainerEvent(ADD_CHILD_EVENT, child);
}
}
我们查看这个方法发现是private修饰的,我们还发现这个内里边还有一个addChild方法调了它:
public voidaddChild(Container child) {
if (System.getSecurityManager() !=null) {
PrivilegedAction dp =
new PrivilegedAddChild(child);
AccessController.doPrivileged(dp);
} else {
addChildInternal(child);
}
}
这个方法是public进行修饰的,但是那个地方调用就了这个方法呢?这个时候,我们又得联想到server.xml的文档结构了,然后再查找Catalina中的代码:
digester.addRuleSet(newHostRuleSet("Server/Service/Engine/"));
然后再查看HostRuleSet中的addRuleInstances源码:
digester.addObjectCreate(prefix+ "Host",
"org.apache.catalina.core.StandardHost",
"className");
digester.addSetProperties(prefix +"Host");
digester.addRule(prefix +"Host",
newCopyParentClassLoaderRule(digester));
digester.addRule(prefix +"Host",
newLifecycleListenerRule
(digester,
"org.apache.catalina.startup.HostConfig",
"hostConfigClass"));
digester.addSetNext(prefix +"Host",
"addChild",
"org.apache.catalina.Container");
这个时候,我们就明白了,原来children里边存着StandardHost对象集合,所以这里有将standardEngine的启动传递给了standardHost对象了
第6点,我们查看pipeline属性代码可以知道:
protectedPipeline pipeline = new StandardPipeline(this);
初始化的时候就讲pipeline赋值了一个StandardPipeline对象,同时将standardEngine作为构造参数传入到对象中,这个地方我们要注意下,在standardEngine的构造方法其实对pipeline进行了一些属性赋值:
public StandardEngine() {
super();
pipeline.setBasic(new StandardEngineValve());
}
我们可以根据digester解析xml的机制,创建standardEngine的时候,就已经为pipeline的basic设置了StandardEngineValve对象,但是根据StandardEngineValve的继承关系,我们只到其实并没有实现lifecycle接口,所以就不执行start方法
分析完了之后,我们来个小综述:
1, standardEngine的start法其实是调用了父类containerBase的start方法
2, containerBase的start方法,利用监听者模式,执行了监听者EngineConfig的监听方法
3, 设置了mappers的值为StandardEngineMapper
利用digester机制,为child增加了standardHost对象,并将standardEngine的start方法传递给了standardHost
standardEngine启动流程图如下:
standardEngine启动关系类图如下:
相关文章推荐
- tomcat源码研读笔记—tomcat的启动之六 StandardWrapper的启动
- tomcat源码研读笔记—tomcat的初始化之一 StandardServer的初始化
- tomcat源码研读笔记—tomcat的初始化之二 StandardService的初始化
- tomcat源码研读笔记—tomcat的启动之七 HttpConnector的启动
- tomcat源码研读笔记—tomcat的启动之一 StandardServer的启动
- tomcat源码研读笔记—tomcat的启动之二 StandardService的启动
- tomcat源码研读笔记—tomcat的启动之四 StandardHost的启动
- tomcat源码研读笔记—tomcat的接收请求之四 StandardContext接收请求
- tomcat源码研读笔记—tomcat的启动之五 StandardContext的启动
- tomcat源码研读笔记—Catalina类
- 4000 Tomcat源码分析 -- StandardContext的启动
- Tomcat源码分析(3)--StandardServer类中涉及到的初始化和启动
- Tomcat源码阅读之Engine启动过程
- tomcat源码研读笔记—tomcat的初始化之三 HttpConnector的初始化
- tomcat源码研读笔记—tomcat的接收请求之一 HttpProcessor接收请求
- tomcat源码研读笔记—tomcat的接收请求之三 StandardHost接收请求
- Tomcat源码阅读之StandardEngine分析与Valve的设计
- tomcat7启动流程源码分析
- hadoop2.5.2学习及实践笔记(四)—— namenode启动过程源码概览
- tomcat源码分析(二)启动---Debug方式