前面已经知道,server管理包含多个service,我们从类的结构看起 1.整体类的继承结构 server.xml结构
<!--
每个Service元素只能有一个Engine元素.元素处理在同一个<Service>中所有<Connector>元素接收到的客户请求
-->
<Service name="Catalina">
<!-- 1. 属性说明
name:Service的名称
-->
<!--2. 一个或多个excecutors -->
<!--
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="150" minSpareThreads="4"/>
-->
<!--
3.Connector元素:
由Connector接口定义.<Connector>元素代表与客户程序实际交互的组件,它负责接收客户请求,以及向客户返回响应结果.
-->
<Connector port="80" maxHttpHeaderSize="8192"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="100"
connectionTimeout="20000" disableUploadTimeout="true" />
<!-- 属性说明
port:服务器连接器的端口号,该连接器将在指定端口侦听来自客户端的请求。
enableLookups:如果为true,则可以通过调用request.getRemoteHost()进行DNS查询来得到远程客户端的实际主机名;
若为false则不进行DNS查询,而是返回其ip地址。
redirectPort:服务器正在处理http请求时收到了一个SSL传输请求后重定向的端口号。
acceptCount:当所有可以使用的处理请求的线程都被用光时,可以放到处理队列中的请求数,超过这个数的请求将不予处理,而返回Connection refused错误。
connectionTimeout:等待超时的时间数(以毫秒为单位)。
maxThreads:设定在监听端口的线程的最大数目,这个值也决定了服务器可以同时响应客户请求的最大数目.默认值为200。
protocol:必须设定为AJP/1.3协议。
address:如果服务器有两个以上IP地址,该属性可以设定端口监听的IP地址,默认情况下,端口会监听服务器上所有IP地址。
minProcessors:服务器启动时创建的处理请求的线程数,每个请求由一个线程负责。
maxProcessors:最多可以创建的处理请求的线程数。
minSpareThreads:最小备用线程 。
maxSpareThreads:最大备用线程。
debug:日志等级。
disableUploadTimeout:禁用上传超时,主要用于大数据上传时。
-->
<Connector port="8009" enableLookups="false" redirectPort="8443" protocol="AJP/1.3" />
<!-- 负责和其他HTTP服务器建立连接。在把Tomcat与其他HTTP服务器集成时就需要用到这个连接器。 -->
<!--
4. Engine
-->
<Engine name="Catalina" defaultHost="localhost">
</Engine>
</Service>
如上面所示,我们要从,engine,connector,Executor,engine四个组件介绍
service接口
public interface Service extends Lifecycle {
public Engine getContainer();
public void setContainer(Engine engine);
public String getName();
public void setName(String name);
public Server getServer();
public void setServer(Server server);
public ClassLoader getParentClassLoader();
public void setParentClassLoader(ClassLoader parent);
public String getDomain();
public void addConnector(Connector connector);
public Connector[] findConnectors();
public void removeConnector(Connector connector);
public void addExecutor(Executor ex);
public Executor[] findExecutors();
public Executor getExecutor(String name);
public void removeExecutor(Executor ex);
Mapper getMapper();
}
StandardService实现
private String name = null;
private Server server = null;
protected final PropertyChangeSupport support = new PropertyChangeSupport(this);
protected Connector connectors[] = new Connector[0];
private final Object connectorsLock = new Object();
protected final ArrayList<Executor> executors = new ArrayList<>();
private Engine engine = null;
private ClassLoader parentClassLoader = null;
protected final Mapper mapper = new Mapper();
protected final MapperListener mapperListener = new MapperListener(this);
如上的结构可以看出,service包括,一个engine,一个mapper,多个connectors,多个executor,一个mapperListener。
private Engine engine = null;
@Override
public Engine getContainer() {
return engine;
}
@Override
public void setContainer(Engine engine) {
Engine oldEngine = this.engine;
if (oldEngine != null) {
oldEngine.setService(null);
}
this.engine = engine;
if (this.engine != null) {
this.engine.setService(this);
}
if (getState().isAvailable()) {
if (this.engine != null) {
try {
this.engine.start();
} catch (LifecycleException e) {
log.error(sm.getString("standardService.engine.startFailed"), e);
}
}
try {
mapperListener.stop();
} catch (LifecycleException e) {
log.error(sm.getString("standardService.mapperListener.stopFailed"), e);
}
try {
mapperListener.start();
} catch (LifecycleException e) {
log.error(sm.getString("standardService.mapperListener.startFailed"), e);
}
if (oldEngine != null) {
try {
oldEngine.stop();
} catch (LifecycleException e) {
log.error(sm.getString("standardService.engine.stopFailed"), e);
}
}
}
support.firePropertyChange("container", oldEngine, this.engine);
}
*/
protected Connector connectors[] = new Connector[0];
private final Object connectorsLock = new Object();
@Override
public void addConnector(Connector connector) {
synchronized (connectorsLock) {
connector.setService(this);
Connector results[] = new Connector[connectors.length + 1];
System.arraycopy(connectors, 0, results, 0, connectors.length);
results[connectors.length] = connector;
connectors = results;
}
try {
if (getState().isAvailable()) {
connector.start();
}
} catch (LifecycleException e) {
throw new IllegalArgumentException(
sm.getString("standardService.connector.startFailed", connector), e);
}
support.firePropertyChange("connector", null, connector);
}
public ObjectName[] getConnectorNames() {
ObjectName results[] = new ObjectName[connectors.length];
for (int i=0; i<results.length; i++) {
results[i] = connectors[i].getObjectName();
}
return results;
}
@Override
public Connector[] findConnectors() {
return connectors;
}
@Override
public void removeConnector(Connector connector) {
synchronized (connectorsLock) {
int j = -1;
for (int i = 0; i < connectors.length; i++) {
if (connector == connectors[i]) {
j = i;
break;
}
}
if (j < 0)
return;
if (connectors[j].getState().isAvailable()) {
try {
connectors[j].stop();
} catch (LifecycleException e) {
log.error(sm.getString(
"standardService.connector.stopFailed",
connectors[j]), e);
}
}
connector.setService(null);
int k = 0;
Connector results[] = new Connector[connectors.length - 1];
for (int i = 0; i < connectors.length; i++) {
if (i != j)
results[k++] = connectors[i];
}
connectors = results;
support.firePropertyChange("connector", connector, null);
}
}
- Executor相关
这里主要是对executor的增删改,同时增删的时候,注意容器的状态
@Override
public void addExecutor(Executor ex) {
synchronized (executors) {
if (!executors.contains(ex)) {
executors.add(ex);
if (getState().isAvailable()) {
try {
ex.start();
} catch (LifecycleException x) {
log.error(sm.getString("standardService.executor.start"), x);
}
}
}
}
}
@Override
public Executor[] findExecutors() {
synchronized (executors) {
Executor[] arr = new Executor[executors.size()];
executors.toArray(arr);
return arr;
}
}
@Override
public Executor getExecutor(String executorName) {
synchronized (executors) {
for (Executor executor: executors) {
if (executorName.equals(executor.getName()))
return executor;
}
}
return null;
}
@Override
public void removeExecutor(Executor ex) {
synchronized (executors) {
if ( executors.remove(ex) && getState().isAvailable() ) {
try {
ex.stop();
} catch (LifecycleException e) {
log.error(sm.getString("standardService.executor.stop"), e);
}
}
}
}
Lifecycle相关模板方法
@Override
protected void initInternal() throws LifecycleException {
super.initInternal();
if (engine != null) {
engine.init();
}
for (Executor executor : findExecutors()) {
if (executor instanceof JmxEnabled) {
((JmxEnabled) executor).setDomain(getDomain());
}
executor.init();
}
mapperListener.init();
synchronized (connectorsLock) {
for (Connector connector : connectors) {
connector.init();
}
}
}
protected void startInternal() throws LifecycleException {
if(log.isInfoEnabled()) {
log.info(sm.getString("standardService.start.name", this.name));
}
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) {
try {
if (connector.getState() != LifecycleState.FAILED) {
connector.start();
}
} catch (Exception e) {
log.error(sm.getString(
"standardService.connector.startFailed",
connector), e);
}
}
}
}
mapperListener 的作用是在 start 的时候将容器类对象注册到 Mapper 对象中。 Mapper是 Tomcat 处理 Http 请求时非常重要的组件。Tomcat 使用 Mapper 来处理一个 Request 到 Host、Context 的映射关系,从而决定使用哪个 Service 来处理请求。
mapperListener的startInternal方法:
public void startInternal() throws LifecycleException {
setState(LifecycleState.STARTING);
Engine engine = service.getContainer();
if (engine == null) {
return;
}
findDefaultHost();
addListeners(engine);
Container[] conHosts = engine.findChildren();
for (Container conHost : conHosts) {
Host host = (Host) conHost;
if (!LifecycleState.NEW.equals(host.getState())) {
registerHost(host);
}
}
}
private void findDefaultHost() {
Engine engine = service.getContainer();
String defaultHost = engine.getDefaultHost();
boolean found = false;
if (defaultHost != null && defaultHost.length() > 0) {
Container[] containers = engine.findChildren();
for (Container container : containers) {
Host host = (Host) container;
if (defaultHost.equalsIgnoreCase(host.getName())) {
found = true;
break;
}
String[] aliases = host.findAliases();
for (String alias : aliases) {
if (defaultHost.equalsIgnoreCase(alias)) {
found = true;
break;
}
}
}
}
if (found) {
mapper.setDefaultHostName(defaultHost);
} else {
log.error(sm.getString("mapperListener.unknownDefaultHost", defaultHost, service));
}
}
findDefaultHost() 是主要是找出 defaultHost ,并调用 mapper.setDefaultHostName(defaultHost); 这个 defaultHost 是 server.xml 的 标签的属性,一般都是 “localHost”。
- addListeners(engine) 方法
在这里插入代码片
private void addListeners(Container container) {
container.addContainerListener(this);
container.addLifecycleListener(this);
for (Container child : container.findChildren()) {
addListeners(child);
}
}
这个方法的作用是,将 MapperListener 这个监听器添加到 Engine 及其子容器中。
- registerHost
调用 registerHost方法来注册 Engine 的字容器 Host。
private void registerHost(Host host) {
String[] aliases = host.findAliases();
mapper.addHost(host.getName(), aliases, host);
for (Container container : host.findChildren()) {
if (container.getState().isAvailable()) {
registerContext((Context) container);
}
}
findDefaultHost();
if(log.isDebugEnabled()) {
log.debug(sm.getString("mapperListener.registerHost",
host.getName(), domain, service));
}
}
registerHost 方法先调用 mapper.addHost,然后调用 registerContext 方法注册 Host 的子容器 Context。 mapper.addHost 方法是将 Host 加入的 Mapper 类的的成员变量MappedHost[] hosts 中。
private void registerContext(Context context) {
String contextPath = context.getPath();
if ("/".equals(contextPath)) {
contextPath = "";
}
Host host = (Host)context.getParent();
WebResourceRoot resources = context.getResources();
String[] welcomeFiles = context.findWelcomeFiles();
List<WrapperMappingInfo> wrappers = new ArrayList<>();
for (Container container : context.findChildren()) {
prepareWrapperMappingInfo(context, (Wrapper) container, wrappers);
if(log.isDebugEnabled()) {
log.debug(sm.getString("mapperListener.registerWrapper",
container.getName(), contextPath, service));
}
}
mapper.addContextVersion(host.getName(), host, contextPath,
context.getWebappVersion(), context, welcomeFiles, resources,
wrappers);
if(log.isDebugEnabled()) {
log.debug(sm.getString("mapperListener.registerContext",
contextPath, service));
}
}
registerContext 里先获取一些对象,比如 WebResourceRoot 对象、WrapperMappingInfo 对象,然后调用 mapper.addContextVersion。 Mapper#addContextVersion 方法比较琐细,就不细讲了。 其主要逻辑是将 Context 对象,以及 Context 的子容器 Wrapper 对象,每一个都分别构建一个对应的 MappedContext 和 MappedWrapper 对象, 然后把 MappedContext 和 MappedWrapper 塞进 ContextVersion 对象中, 最后把 Context 和 ContextVersion 的对应关系放在 Mapper 对象的一个 Map 里。 这里的 MappedContext 和 MappedWrapper 在 Tomcat 处理 Http 请求的时候是比较关键的。 registerHost 最后再更新了一下可能发生改变里的的 defaultHost
|