在上一章 查看tomcat启动文件都干点啥---Catalina.java 中说道了构造Server,,这次尝试着说一下Tomcat中Server的内容,首先看一下org.apache.catalina.Server接口中定义的方法:
从这里至少可以看出Server中包含很多Service,通过实现如下接口添加一个新的Service到Services的集合中,或者从集合中删除指定的Service:
public
void
addService(Service service);
public
void
removeService(Service service);
通过实现如下接口来完成通过service的名称返回Service的操作:
public
Service findService(String name);
通过实现如下接口来完成获取返回Server中所有Service的操作:
public
Service[] findServices();
对于Server的网络内容的设置和获取通过如下方法,包括设置地址,端口:
public
int
getPort();
public
void
setPort(
int
port);
public
String getAddress();
public
void
setAddress(String address);
获取和指定shotdown命令:
public
String getShutdown();
public
void
setShutdown(String shutdown);
获取和设置父类的加载器:
public
ClassLoader getParentClassLoader();
public
void
setParentClassLoader(ClassLoader parent);
如果设置了Catalina,那么也提供获取和设置的方法:
public
Catalina getCatalina();
public
void
setCatalina(Catalina catalina);
通过Server接口至少我们能够得出结论:Server中包含多个Service对象。
结构如下:
值得注意的是Server借口继承了Lifecycle接口,
public
interface
Server
extends
Lifecycle
Lifecycle 接口就是来控制Server极其组件的生命周期的,组件实现Lifecycle借口,就可以提供一致化的机制来启动和停止组件。下面看一下 Lifecycle的内容:
首先是一些常量列表,小插曲,在Tomcat7.0.53中,tomcat在此处的注释有小问题,有兴趣的人可以看一下。
//
组件初始化之前的事件
public
static
final
String BEFORE_INIT_EVENT = "before_init"
;
//
组件初始化之后的事件
public
static
final
String AFTER_INIT_EVENT = "after_init"
;
//
组件start的事件
public
static
final
String START_EVENT = "start"
;
//
组件start之前的事件
public
static
final
String BEFORE_START_EVENT = "before_start"
;
//
组件start之后的事件
public
static
final
String AFTER_START_EVENT = "after_start"
;
//
组件stop之后的事件
public
static
final
String STOP_EVENT = "stop"
;
//
组件stop之前的事件
public
static
final
String BEFORE_STOP_EVENT = "before_stop"
;
//
组件stop之后的事件
public
static
final
String AFTER_STOP_EVENT = "after_stop"
;
//
组件destrop之后的事件
public
static
final
String AFTER_DESTROY_EVENT = "after_destroy"
;
//
组件destrop之前的事件
public
static
final
String BEFORE_DESTROY_EVENT = "before_destroy"
;
//
组件periodic的事件
public
static
final
String PERIODIC_EVENT = "periodic";
下面就是Lifecycle接口定义的方法列表:
既然Server中包含的主要对象就是Service,实现了Service就是对外提供服务了,下面在看一下Service的接口定义:
看了定义的方法之后,很想逐一说明一下,可能会发现问题:
在Service中添加或移除connector的方法:
public
void
addConnector(Connector connector);
public
void
removeConnector(Connector connector);
说明在每个Service中有多个Connector。
在Service中添加或移除Executor的方法:
public
void
addExecutor(Executor ex);
public
void
removeExecutor(Executor ex);
返回所有Connector的方法:
public
Connector[] findConnectors();
返回所有executor的方法:
public
Executor[] findExecutors();
设置和获取Container的方法:
public
Container getContainer();
public
void
setContainer(Container container);
获取和设置关联的Server对象的方法:
public
void
setServer(Server server);
public
Server getServer();
给Service设置获取名称的方法:
public
void
setName(String name);
public
String getName();
以上就是Service接口定义的主要方法,得出在Service中包含一个或多个Connector,包含一个或多个Executors和一个Container对象。接着上面的Server---Service图我们可以得出如下关系图:
|---------Connector
Server----Service----|
|----------Container
由此可知在Tomcat中的两个重要的组件就是Connector和Container。下面我们着重看一下Connector和Container。
Container的主要功能是执行从客户端接收的请求,然后给出回应。看一下Container接口定义的方法:
添加,删除和获取一个子Container:
public
void
addChild(Container child);
public
void
removeChild(Container child);
public
Container findChild(String name);
public
Container[] findChildren();
对应的在Container中就应该有设置和获取父Container的方法:
public
void
setParent(Container container);
public
Container getParent();
在Container中添加,移除和获取事件监听器:
public
void
addContainerListener(ContainerListener listener);
public
void
removeContainerListener(ContainerListener listener);
public
ContainerListener[] findContainerListeners();
在Container中添加,移除和获取属性变更监听器:
public
void
addPropertyChangeListener(PropertyChangeListener listener);
public
void
removePropertyChangeListener(PropertyChangeListener listener);
触发Container事件:
public
void
fireContainerEvent(String type, Object data);
记录指向这个container的请求与响应的日志:
public
AccessLog getAccessLog();
设置和获取作用在该container及其子container上的方法的延迟时间,单位秒:
public
void
setBackgroundProcessorDelay(
int
delay);
public
int
getBackgroundProcessorDelay();
设置和获取相关的集群:
public
void
setCluster(Cluster cluster);
public
Cluster getCluster();
设置和获取Loadeer:
public
void
setLoader(Loader loader);
public
Loader getLoader();
设置和获取负责管理该Container对应Session pool的Manager对象:
public
void
setManager(Manager manager);
public
Manager getManager();
设置和获取Container的名字描述:
public
void
setName(String name);
public
String getName();
设置和获取父类的ClassLoader:
public
void
setParentClassLoader(ClassLoader parent);
public
ClassLoader getParentClassLoader();
获取Pipeline,负责管理该Container中的相关值:
public
Pipeline getPipeline();
设置和获取Container的上下文资源:
public
void
setResources(DirContext resources);
public
DirContext getResources();
设置和获取启动和停止children container的线程数,可以并行的启动和停止子container:
public
void
setStartStopThreads(
int
startStopThreads);
public
int
getStartStopThreads();
Connector类中的变量已经方法实现如下:
代表一个Container的入口的变量:
protected
Adapter adapter =
null
;
实现Servlet的API规则匹配的变量:
protected
Mapper mapper =
new
Mapper();
是否允许Trace:
protected
boolean
allowTrace =
false
;
异步请求的超时时间:
protected
long
asyncTimeout = 10000;
是否允许DNS查找的标记:
protected
boolean
enableLookups =
false
;
Mapper监听器:
protected
MapperListener mapperListener =
new
MapperListener(mapper,
this
);
GET和POST方法中,Container解析的最大的参数个数限制(默认值为1000,当设置数值小于0时,表示没有限制):
protected
int
maxParameterCount = 10000;
Container接收POST方法传递的最大数据(默认值为2M):
protected
int
maxPostSize = 2 * 1024 * 1024;
在Container认证时候默认保存的最大数据:(默认值4K):
protected
int
maxSavePostSize = 4 * 1024;
一系列以逗号分割的,application/x-www-form-urlencoded形式的方法请求体,以什么方式转化成方法的集合:
protected
String parseBodyMethods = "POST";
通过parseBodyMethods方式确定的方法集合:
protected
HashSet<String> parseBodyMethodsSet;
监听请求端口的数量:(默认值为-1):
protected
int
port = -1;
connector对象将请求重定向到那个Server:
protected
String proxyName =
null
;
connector对象请求重定向到server的哪个端口:
protected
int
proxyPort = 0;
从no-ssl到ssl重定向端口:
protected
int
redirectPort = 443;
通过connector接收到的所有请求的请求方案:
protected
String scheme = "http";
是否给每个接收到的请求设置安全连接标记:
protected
boolean
secure =
false
;
一个String帮助对象:
protected
static
final
StringManager sm =
StringManager.getManager(Constants.Package);
关联的Service对象:
protected
Service service =
null
;
URL编码:
protected
String URIEncoding =
null
;
是否用body编码给URL编码:(不明白)
protected
boolean
useBodyEncodingForURI =
false
;
是否用IP绑定虚拟主机:
protected
boolean
useIPVHosts =
false
;
下面看一下Connector的构造函数:
public
Connector() {
this
(
null
);
}
public
Connector(String protocol) {
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);
}
}
Connector的构造函数中第一步是根据
protocol名称HTTP/1.1,AJP/1.3或者protocol handler的类的全路径名称,下面是setProtocol方法的代码实现:
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.coyote.ajp.AjpProtocol"
);
}
else
if
(protocol !=
null
) {
setProtocolHandlerClassName(protocol);
}
}
然后根据setProtocol方法设置的protocol handler进行实例化,在setProtocol方法中调用的setProtocolHandlerClassName方法,如下:
public
void
setProtocolHandlerClassName(String protocolHandlerClassName) {
this
.protocolHandlerClassName =
protocolHandlerClassName;
}
给connector的变量protocolHandlerClassName赋值,然后根据protocolHandlerClassName的值进行实例化。进而赋值给protocolHandler 变量。
然后是方法createObjectNameKeyProperties,该方法的作用是将请求的address参数拼接成字符串,包括type,port。下面是代码实现:
protected
String createObjectNameKeyProperties(String type) {
Object addressObj
= getProperty("address"
);
StringBuilder sb
=
new
StringBuilder("type="
);
sb.append(type);
sb.append(
",port="
);
int
port =
getPort();
if
(port > 0
) {
sb.append(getPort());
}
else
{
sb.append(
"auto-"
);
sb.append(getProperty(
"nameIndex"
));
}
String address
= ""
;
if
(addressObj
instanceof
InetAddress) {
address
=
((InetAddress) addressObj).getHostAddress();
}
else
if
(addressObj !=
null
) {
address
=
addressObj.toString();
}
if
(address.length() > 0
) {
sb.append(
",address="
);
sb.append(ObjectName.quote(address));
}
return
sb.toString();
}
创建一个Request对象,Request是一个对Coyote Request的封装,Coyote 这个东西很奇怪,是狼的意思,也不知道为什么外国人喜欢用动物名来给一个技术命名,hadoop,hive,pig等,说Coyote其实是对Socket的一个封装,将Socket的请求和相应封装成一个个Request和Response,具体如何封装,都包涵什么信息等内容以后展开说明:
public
Request createRequest() {
Request request
=
new
Request();
request.setConnector(
this
);
return
(request);
}
创建一个Response对象:
public
Response createResponse() {
Response response
=
new
Response();
response.setConnector(
this
);
return
(response);
}
这里面值得注意的地方就是在request和response中,都有setConnector方法,所有connector是request和response的一个属性。
下面看方法destroyInternal,这个方法是在LifecycleMBeanBase类中定义的,用来销毁mapperListener,protocolHandler从Service中移除这个Connector对象,代码实现如下:
@Override
protected
void
destroyInternal()
throws
LifecycleException {
mapperListener.destroy();
try
{
protocolHandler.destroy();
}
catch
(Exception e) {
throw
new
LifecycleException
(sm.getString
(
"coyoteConnector.protocolHandlerDestroyFailed"
), e);
}
if
(getService() !=
null
) {
getService().removeConnector(
this
);
}
super
.destroyInternal();
}
设置和获取是否允许Trace方法的执行:
public
void
setAllowTrace(
boolean
allowTrace) {
this
.allowTrace =
allowTrace;
setProperty(
"allowTrace"
, String.valueOf(allowTrace));
}
public
boolean
getAllowTrace() {
return
(
this
.allowTrace);
}
设置和获取异步请求的过期时间:
public
void
setAsyncTimeout(
long
asyncTimeout) {
this
.asyncTimeout=
asyncTimeout;
setProperty(
"asyncTimeout"
, String.valueOf(asyncTimeout));
}
public
long
getAsyncTimeout() {
return
asyncTimeout;
}
配置和获取参数,参数这部分在前面的章节已经提到过了:
public
void
setAttribute(String name, Object value) {
setProperty(name, String.valueOf(value));
}
public
Object getAttribute(String name) {
return
getProperty(name);
}
剩下的方法都是设置和获取前面定义的变量的值。
Server的主要接口已经介绍完了,下面看一下一些关键类的实现:
Server接口的标准实现是StandardServer类,同时StandServer也继承了LifecycleMBeanBase类,看一下StandardServer中几个重要方法的实现:
找几个重要的方法说明一下:
向保存Connector的数组中添加新的Connector对象的方法addConnector,代码实现如下:
public
void
addConnector(Connector connector) {
synchronized
(connectors) {
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
(getState().isAvailable()) {
try
{
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和Serice做关联,connector.setService(this),然后将要添加的connector对象添加到保存Connector对象的数组中,此处使用数组,完全是处于效率的考虑。然后查看当前Server对象的状态,如果状态合法的话,那么启动添加的connector对象。然后在更改此Connector的状态。
返回Connector集合:
@Override
public
Connector[] findConnectors() {
return
(connectors);
}
在Connector集合中移除connector:
public
void
removeConnector(Connector connector) {
synchronized
(connectors) {
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;
//
Report this property change to interested listeners
support.firePropertyChange("connector", connector,
null
);
}
}
首先遍历Connector集合,找到要移除的connector,如果指定的connector对象状态合法,那么调用该connector的stop方法,然后将指定的connector对象关联的Server置为null,剩下的内容就是整理移除connector对象的Connector集合。
设置Container方法,该container对象处理Service中所有connector中的请求:
public
void
setContainer(Container container) {
Container oldContainer
=
this
.container;
if
((oldContainer !=
null
) && (oldContainer
instanceof
Engine))
((Engine) oldContainer).setService(
null
);
this
.container =
container;
if
((
this
.container !=
null
) && (
this
.container
instanceof
Engine))
((Engine)
this
.container).setService(
this
);
if
(getState().isAvailable() && (
this
.container !=
null
)) {
try
{
this
.container.start();
}
catch
(LifecycleException e) {
//
Ignore
}
}
if
(getState().isAvailable() && (oldContainer !=
null
)) {
try
{
oldContainer.stop();
}
catch
(LifecycleException e) {
//
Ignore
}
}
//
Report this property change to interested listeners
support.firePropertyChange("container", oldContainer,
this
.container);
}
首先是处理这个Server中原有的Container,原来可能有Container也有可能没有,所以要做判断,如果存在的话,解除和Service的关联,然后要处理新的container对象。关联Service,启动Container。
由于Service中只有一个Container,所以没有移除Container方法,在设置的时候其实是完成了删除更新的操作。
看一下startInternal方法:
protected
void
startInternal()
throws
LifecycleException {
if
(log.isInfoEnabled())
log.info(sm.getString(
"standardService.start.name",
this
.name));
setState(LifecycleState.STARTING);
//
Start our defined Container first
if
(container !=
null
) {
synchronized
(container) {
container.start();
}
}
synchronized
(executors) {
for
(Executor executor: executors) {
executor.start();
}
}
//
Start our defined Connectors second
synchronized
(connectors) {
for
(Connector connector: connectors) {
try
{
//
If it has already failed, don't try and start it
if
(connector.getState() !=
LifecycleState.FAILED) {
connector.start();
}
}
catch
(Exception e) {
log.error(sm.getString(
"standardService.connector.startFailed"
,
connector), e);
}
}
}
}
该方法就是逐一启动Service中的组件,Container,Executor,Connector。
stopInternal方法:
protected
void
stopInternal()
throws
LifecycleException {
//
Pause connectors first
synchronized
(connectors) {
for
(Connector connector: connectors) {
try
{
connector.pause();
}
catch
(Exception e) {
log.error(sm.getString(
"standardService.connector.pauseFailed"
,
connector), e);
}
}
}
if
(log.isInfoEnabled())
log.info(sm.getString(
"standardService.stop.name",
this
.name));
setState(LifecycleState.STOPPING);
//
Stop our defined Container second
if
(container !=
null
) {
synchronized
(container) {
container.stop();
}
}
//
Now stop the connectors
synchronized
(connectors) {
for
(Connector connector: connectors) {
if
(!
LifecycleState.STARTED.equals(
connector.getState())) {
//
Connectors only need stopping if they are currently
//
started. They may have failed to start or may have been
//
stopped (e.g. via a JMX call)
continue
;
}
try
{
connector.stop();
}
catch
(Exception e) {
log.error(sm.getString(
"standardService.connector.stopFailed"
,
connector), e);
}
}
}
synchronized
(executors) {
for
(Executor executor: executors) {
executor.stop();
}
}
}
由这两个方法也能看出来Lifecycle对于个个组件生命周期的一致的生命周期的管理机制。
其实最开始想用本章说一下如何构建Server,但是觉得还是有必要将Server中的内容展开说明一下,在说如果构建的话可能更好理解。所以就有了这个只是具有说明意义的一节。

