上节看了容器的初始化和启动,知道了Tomcat初始化和启动都是由Server.init(),Server.start(),层层向下依次触发各个组件的initInternal(),startInternal()方法进行初始化和启动,从本片开始,就从各组件的初始化和启动开始读源码(本文Tomcat8.5)
本文的Service实现类是StandardService,内部从配置文件中看到,内部是多个Connector和一个Engine组成,来看代码
initInternal() / startInternal()
就是调用各子组件(Engine\Connector\Mapper\Executor)的初始化和启动方法
public class StandardService extends LifecycleMBeanBase implements Service {
// 父组件Server的引用
private Server server = null;
// 多个Connector,每种连接一个Connector http,https,向相同协议不同端口的连接等
protected Connector connectors[] = new Connector[0];
// 用来synchronized
private final Object connectorsLock = new Object();
// Service下 和Connector和Engine同级别的组件Executor,StandardThreadExecutor
// ThreadPoolExecutor的封装
protected final ArrayList<Executor> executors = new ArrayList<>();
// 子组件Engine
private Engine engine = null;
protected final Mapper mapper = new Mapper();
protected final MapperListener mapperListener = new MapperListener(this);
@Override
protected void initInternal() throws LifecycleException {
// 注册当前对象MBean
super.initInternal();
// 初始化engine
if (engine != null) {
engine.init();
}
// 初始化Executor
for (Executor executor : findExecutors()) {
if (executor instanceof JmxEnabled) {
((JmxEnabled) executor).setDomain(getDomain());
}
executor.init();
}
// 初始化mapperListener,只是注册JMX
mapperListener.init();
// 初始化Connector
synchronized (connectorsLock) {
for (Connector connector : connectors) {
try {
connector.init();
} catch (Exception e) {
String message = sm.getString(
"standardService.connector.initFailed", connector);
log.error(message, e);
if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE"))
throw new LifecycleException(message);
}
}
}
}
protected void startInternal() throws LifecycleException {
// 设置Starting状态
setState(LifecycleState.STARTING);
// 启动Engine
if (engine != null) {
synchronized (engine) {
engine.start();
}
}
// 启动executor
synchronized (executors) {
for (Executor executor: executors) {
executor.start();
}
}
//mapperListener启动
mapperListener.start();
// Connector启动
synchronized (connectorsLock) {
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);
}
}
}
}
}
Connector和Engine下节看
Mapper
对请求进行路由, Mapper中有MappedHost数组,Mapper内部类有MappedHost\MappedContext\MappedWrapper 几种,和Container容器有四个子接口Engine,Host,Context,Wrapper一一对应
目的是请求来时快速查找匹配的具体的wrapper(Servlet)
public final class Mapper {
volatile MappedHost[] hosts = new MappedHost[0];
}
在tomcat服务器中,有多个service,每个service有一个engine,而一个engine可以部署多个host,一个host又可以部署多个context,一个context多个wrapper,Mapper类中也符合这个层次。
MapperListener
查询当前Engine所部署的相关应用更新到mapper中,并监听Engine下容器动态更新mapper
public class MapperListener extends LifecycleMBeanBase
implements ContainerListener, LifecycleListener {
private final Mapper mapper;
private final Service service;
public MapperListener(Service service) {
this.service = service;
this.mapper = service.getMapper();
}
}
首先MapperListener继承 LifecycleMBeanBase,说明对象的启动会被注册到jmx上面去,其次实现了两个Listener,LifecycleListener之前见过,监听顶层的生命周期变更事件触发lifecycleEvent()方法,ContainerListener监听容器Container的变更事件触发containerEvent()方法
public interface ContainerListener {
public void containerEvent(ContainerEvent event);
}
org.apache.catalina.mapper.MapperListener#startInternal
@Override
public void startInternal() throws LifecycleException {
// 设置启动状态
setState(LifecycleState.STARTING);
Engine engine = service.getContainer();
if (engine == null) {
return;
}
// <Engine name="Catalina" defaultHost="localhost">
// 获取defaultHost属性, 并检查是否存在对应的<Host >标签
findDefaultHost();
// 将Engine及其子容器都注册这个MapperListener对象
addListeners(engine);
// 获取engine的所有Host配置,注册到Mapper中
// 注册host又会把其下所有context注册,接着往下注册所有wrapper
Container[] conHosts = engine.findChildren();
for (Container conHost : conHosts) {
Host host = (Host) conHost;
if (!LifecycleState.NEW.equals(host.getState())) {
// Registering the host will register the context and wrappers
registerHost(host);
}
}
}
private void registerHost(Host host) {
String[] aliases = host.findAliases();
// mapper中增加host
mapper.addHost(host.getName(), aliases, host);
// 注册context到mapper
for (Container container : host.findChildren()) {
if (container.getState().isAvailable()) {
registerContext((Context) container);
}
}
}
org.apache.catalina.mapper.MapperListener#containerEvent
监听器回调方法,根据事件注册或移除监听器,更新mapper
org.apache.catalina.mapper.MapperListener#lifecycleEvent
也是根据事件更新mapper