一、Server和Service的实例化
Catalina.createStartDigester();中Server对象的创建。
digester.addObjectCreate("Server",
"org.apache.catalina.core.StandardServer",
"className");
digester.addSetProperties("Server");
digester.addSetNext("Server",
"setServer",
"org.apache.catalina.Server");
Catalina类继承自Embedded,而Embedded extends StandardService implements Lifecycle
调用Catalina的setServer方法其实是调用StandardService的setServer
public void setServer(Server server) {
this.server = server;
}
Server对象的创建没什么悬念。看看Service对象:
digester.addObjectCreate("Server/Service",
"org.apache.catalina.core.StandardService",
"className");
digester.addSetProperties("Server/Service");
digester.addSetNext("Server/Service",
"addService",
"org.apache.catalina.Service");
StandardService对象创建后,会调用StandardServer的addService方法:
public void addService(Service service) {
service.setServer(this);
synchronized (services) {
Service results[] = new Service[services.length + 1];
System.arraycopy(services, 0, results, 0, services.length);
results[services.length] = service;
services = results;
if (initialized) {
try {
service.initialize();
} catch (LifecycleException e) {
log.error(e);
}
}
if (started && (service instanceof Lifecycle)) {
try {
((Lifecycle) service).start();
} catch (LifecycleException e) {
;
}
}
// Report this property change to interested listeners
support.firePropertyChange("service", null, service);
}
}
StandardService先关联上StandardServer,然后把它加到StandardServer的service数组,这样就相互关联了。
如果已经初始化,则这个StandardService执行初始化,如果已经启动,也要启动。现在我们还在创建对象的阶段,初始化和启动都不会执行。
二、Connector的实例化
Catalina.createStartDigester();Connector对象的创建规则:
digester.addRule("Server/Service/Connector",
new ConnectorCreateRule());
digester.addRule("Server/Service/Connector",
new SetAllPropertiesRule(new String[]{"executor"}));
digester.addSetNext("Server/Service/Connector",
"addConnector",
"org.apache.catalina.connector.Connector");
解析到<Connector>节点时,Digester会调用ConnectorCreateRule的begin方法,传入的参数是节点的属性。
public void begin(Attributes attributes) throws Exception {
Service svc = (Service)digester.peek();
Executor ex = null;
if ( attributes.getValue("executor")!=null ) {
ex = svc.getExecutor(attributes.getValue("executor"));
}
Connector con = new Connector(attributes.getValue("protocol"));
if ( ex != null ) _setExecutor(con,ex);
digester.push(con);
}
至于创建什么样的Connector,要看属性protocol的值。server.xml默认有两个Connector,一个端口8080,protocol="HTTP/1.1",另一个端口8009,protocol="AJP/1.3"。8080大家都知道,据说后者多用于集群。
Connector的构造方法:
public Connector(String protocol)
throws Exception {
setProtocol(protocol);
// Instantiate protocol handler
try {
Class clazz = Class.forName(protocolHandlerClassName);
this.protocolHandler = (ProtocolHandler) clazz.newInstance();
} catch (Exception e) {
log.error
(sm.getString
("coyoteConnector.protocolHandlerInstantiationFailed", e));
}
}
setProtocol方法,主要为了设置protocalHandlerClassName的值。接着再创建对象。
public void setProtocol(String protocol) {
if (AprLifecycleListener.isAprAvailable()) {
if ("HTTP/1.1".equals(protocol)) {
setProtocolHandlerClassName
("org.apache.coyote.http11.Http11AprProtocol");
} else if ("AJP/1.3".equals(protocol)) {
setProtocolHandlerClassName
("org.apache.coyote.ajp.AjpAprProtocol");
} else if (protocol != null) {
setProtocolHandlerClassName(protocol);
} else {
setProtocolHandlerClassName
("org.apache.coyote.http11.Http11AprProtocol");
}
} else {
if ("HTTP/1.1".equals(protocol)) {
setProtocolHandlerClassName
("org.apache.coyote.http11.Http11Protocol");
} else if ("AJP/1.3".equals(protocol)) {
setProtocolHandlerClassName
("org.apache.jk.server.JkCoyoteHandler");
} else if (protocol != null) {
setProtocolHandlerClassName(protocol);
}
}
}
AprLifecycleListener未被实例化过,会执行else块中的语句。
protocal="HTTP/1.1"的Connector会创建Http11Protocol对象赋值给protocolHandler属性。
回到StandardService.addConnector()上来:
public void addConnector(Connector connector) {
synchronized (connectors) {
connector.setContainer(this.container);
connector.setService(this);
Connector results[] = new Connector[connectors.length + 1];
System.arraycopy(connectors, 0, results, 0, connectors.length);
results[connectors.length] = connector;
connectors = results;
if (initialized) {
try {
connector.initialize();
} catch (LifecycleException e) {
log.error(sm.getString(
"standardService.connector.initFailed",
connector), e);
}
}
if (started && (connector instanceof Lifecycle)) {
try {
((Lifecycle) connector).start();
} catch (LifecycleException e) {
log.error(sm.getString(
"standardService.connector.startFailed",
connector), e);
}
}
// Report this property change to interested listeners
support.firePropertyChange("connector", null, connector);
}
}
Connector要关联StandardService的container,这个container其实是StandardEngine对象。关联StandardService后,将添加到StandardService的connectors数组中。
三、Engine的实例化
Catalina.createStartDigester()配置Engine的规则:
digester.addRuleSet(new EngineRuleSet("Server/Service/"));
digester.addRuleSet():
public void addRuleSet(RuleSet ruleSet) {
String oldNamespaceURI = getRuleNamespaceURI();
String newNamespaceURI = ruleSet.getNamespaceURI();
if (log.isDebugEnabled()) {
if (newNamespaceURI == null) {
log.debug("addRuleSet() with no namespace URI");
} else {
log.debug("addRuleSet() with namespace URI " + newNamespaceURI);
}
}
setRuleNamespaceURI(newNamespaceURI);
ruleSet.addRuleInstances(this);
setRuleNamespaceURI(oldNamespaceURI);
}
这里会调用EngineRuleSet的addRuleInstances()方法进行配置规则,这种折腾来折腾去的设计一般都能称得上设计模式,具体是哪种,待学。
EngineRuleSet.addRuleInstances():
public void addRuleInstances(Digester digester) {
digester.addObjectCreate(prefix + "Engine",
"org.apache.catalina.core.StandardEngine",
"className");
digester.addSetProperties(prefix + "Engine");
digester.addRule(prefix + "Engine",
new LifecycleListenerRule
("org.apache.catalina.startup.EngineConfig",
"engineConfigClass"));
digester.addSetNext(prefix + "Engine",
"setContainer",
"org.apache.catalina.Container");
//Cluster configuration start
digester.addObjectCreate(prefix + "Engine/Cluster",
null, // MUST be specified in the element
"className");
digester.addSetProperties(prefix + "Engine/Cluster");
digester.addSetNext(prefix + "Engine/Cluster",
"setCluster",
"org.apache.catalina.Cluster");
//Cluster configuration end
digester.addObjectCreate(prefix + "Engine/Listener",
null, // MUST be specified in the element
"className");
digester.addSetProperties(prefix + "Engine/Listener");
digester.addSetNext(prefix + "Engine/Listener",
"addLifecycleListener",
"org.apache.catalina.LifecycleListener");
digester.addRuleSet(new RealmRuleSet(prefix + "Engine/"));
digester.addObjectCreate(prefix + "Engine/Valve",
null, // MUST be specified in the element
"className");
digester.addSetProperties(prefix + "Engine/Valve");
digester.addSetNext(prefix + "Engine/Valve",
"addValve",
"org.apache.catalina.Valve");
}
StandardEngine对象出栈的时候,当做StandardService.setContainer()的参数进行赋值,即StandardService的container保存的是StandardEngine对象:
/**
* The Container associated with this Service. (In the case of the
* org.apache.catalina.startup.Embedded subclass, this holds the most
* recently added Engine.)
*/
protected Container container = null;
四、Host的实例化
Catalina.createStartDigester()配置Host的规则:
digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));
addRuleSet实际上会调用HostRuleSet.addRuleInstances()进行配置rule:
public void addRuleInstances(Digester digester) {
digester.addObjectCreate(prefix + "Host",
"org.apache.catalina.core.StandardHost",
"className");
digester.addSetProperties(prefix + "Host");
digester.addRule(prefix + "Host",
new CopyParentClassLoaderRule());
digester.addRule(prefix + "Host",
new LifecycleListenerRule
("org.apache.catalina.startup.HostConfig",
"hostConfigClass"));
digester.addSetNext(prefix + "Host",
"addChild",
"org.apache.catalina.Container");
digester.addCallMethod(prefix + "Host/Alias",
"addAlias", 0);
//Cluster configuration start
digester.addObjectCreate(prefix + "Host/Cluster",
null, // MUST be specified in the element
"className");
digester.addSetProperties(prefix + "Host/Cluster");
digester.addSetNext(prefix + "Host/Cluster",
"setCluster",
"org.apache.catalina.Cluster");
//Cluster configuration end
digester.addObjectCreate(prefix + "Host/Listener",
null, // MUST be specified in the element
"className");
digester.addSetProperties(prefix + "Host/Listener");
digester.addSetNext(prefix + "Host/Listener",
"addLifecycleListener",
"org.apache.catalina.LifecycleListener");
digester.addRuleSet(new RealmRuleSet(prefix + "Host/"));
digester.addObjectCreate(prefix + "Host/Valve",
null, // MUST be specified in the element
"className");
digester.addSetProperties(prefix + "Host/Valve");
digester.addSetNext(prefix + "Host/Valve",
"addValve",
"org.apache.catalina.Valve");
}
1.给Host对象加了一个HostConfig的监听器,到时候调用StandardHost.start()的时候也会调用HostConfig.start()。而HostConfig.start()则会去启动所有部署在tomcat上的项目,这是后话。
2.Host对象出栈的时候是调用StandardEngine的addChild方法进行处理的:
public void addChild(Container child) {
if (!(child instanceof Host))
throw new IllegalArgumentException
(sm.getString("standardEngine.notHost"));
super.addChild(child);
}
继续调用父类ContainerBase的addChild方法:
public void addChild(Container child) {
if (Globals.IS_SECURITY_ENABLED) {
PrivilegedAction dp =
new PrivilegedAddChild(child);
AccessController.doPrivileged(dp);
} else {
addChildInternal(child);
}
}
addChildInternal(child):
private void addChildInternal(Container child) {
if( log.isDebugEnabled() )
log.debug("Add child " + child + " " + this);
synchronized(children) {
if (children.get(child.getName()) != null)
throw new IllegalArgumentException("addChild: Child name '" +
child.getName() +
"' is not unique");
child.setParent(this); // May throw IAE
children.put(child.getName(), child);
// Start child
if (started && startChildren && (child instanceof Lifecycle)) {
boolean success = false;
try {
((Lifecycle) child).start();
success = true;
} catch (LifecycleException e) {
log.error("ContainerBase.addChild: start: ", e);
throw new IllegalStateException
("ContainerBase.addChild: start: " + e);
} finally {
if (!success) {
children.remove(child.getName());
}
}
}
fireContainerEvent(ADD_CHILD_EVENT, child);
}
}
ContainerBase.children是HashMap:
/**
* The child Containers belonging to this Container, keyed by name.
*/
protected HashMap children = new HashMap();
StandardHost和StandardEngine相互关联,多对一的关系。
如果conf/server.xml有Context节点,实例化过程与Host类似。StandardContext和StandardHost也是多对一的关系。
Server(1-N)Service(1-1)Engine(1-N)Host(1-N)Context(1-N)。
Connector(1-N)