对,我就是那个看完一脸懵,回去啃代码的小渣渣
设计就是要找到系统的变化点和不变点。
如果想让一个系统能够对外提供服务,需要创建、组装并启动这些组件;在服务停止的时候,需要释放资源,销毁组件,这是一个动态过程。Tomcat组件之间存在两种关系:
总结来说,就是请求的处理过程是由外层组件来驱动的。
系统中的不变点是:组件的创建、初始化、启动、状态及状态的转化。
变化点:每个组件的初始化(启动)方法。
将不变点抽象出来,就是LifeCycle接口。
因为组件的init()和start()调用是由它的父组件的状态变化触发的,可以把组件的生命周期转换成一个个状态,把状态的转变看作一个事件。子组件注册监听父组件的事件,就是观察者模式。
LifeCycle接口里的LifeCycleState定义如下:
public enum LifecycleState {
NEW(false, null),
INITIALIZING(false, Lifecycle.BEFORE_INIT_EVENT),
INITIALIZED(false, Lifecycle.AFTER_INIT_EVENT),
STARTING_PREP(false, Lifecycle.BEFORE_START_EVENT),
STARTING(true, Lifecycle.START_EVENT),
STARTED(true, Lifecycle.AFTER_START_EVENT),
STOPPING_PREP(true, Lifecycle.BEFORE_STOP_EVENT),
STOPPING(false, Lifecycle.STOP_EVENT),
STOPPED(false, Lifecycle.AFTER_STOP_EVENT),
DESTROYING(false, Lifecycle.BEFORE_DESTROY_EVENT),
DESTROYED(false, Lifecycle.AFTER_DESTROY_EVENT),
FAILED(false, null);
private final boolean available;
private final String lifecycleEvent;
private LifecycleState(boolean available, String lifecycleEvent) {
this.available = available;
this.lifecycleEvent = lifecycleEvent;
}
public boolean isAvailable() {
return available;
}
public String getLifecycleEvent() {
return lifecycleEvent;
}
}
看下Event和State之间的对应关系就比较清楚啦~组件到达相应的状态就触发相应的事件。
LifeCycleBase中对组件的公共逻辑进行了实现,如:
为了避免混淆(突出是继承自抽象类),子类需要实现的方法在这里都统一改了名字。
LifeCycleBase在接口方法init、start、stop、destory
实现里调用子类要实现的方法initInternal、startInternal、stopInternal、destroyInternal
。以init为例:
@Override
public final synchronized void init() throws LifecycleException {
if (!state.equals(LifecycleState.NEW)) {
invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
}
try {
setStateInternal(LifecycleState.INITIALIZING, null, false);
initInternal();
setStateInternal(LifecycleState.INITIALIZED, null, false);
} catch (Throwable t) {
handleSubClassException(t, "lifecycleBase.initFail", toString());
}
}
可以看出状态触发事件是通过setStateInternal
来实现的,setStateInternal
的实现如下:
private synchronized void setStateInternal(LifecycleState state, Object data, boolean check)
throws LifecycleException {
// 状态检查
if (check) {
……
}
// 事件触发
this.state = state;
String lifecycleEvent = state.getLifecycleEvent();
if (lifecycleEvent != null) {
fireLifecycleEvent(lifecycleEvent, data);
}
}
核心就是fireLifecycleEvent。
protected void fireLifecycleEvent(String type, Object data) {
LifecycleEvent event = new LifecycleEvent(this, type, data);
for (LifecycleListener listener : lifecycleListeners) {
listener.lifecycleEvent(event);
}
}
LifeCycleBase中用到的是模板设计模式。
LifeCycleBase负责触发事件,并调用监听器的方法,监听器的注册分为两种情况:
流程说明:
Catalina主要是创建server。
public void start() {
if (getServer() == null) {
load();
}
if (getServer() == null) {
log.fatal(sm.getString("catalina.noServer"));
return;
}
// Start the new server
try {
getServer().start();
} catch (LifecycleException e) {
log.fatal(sm.getString("catalina.serverStartFail"), e);
try {
getServer().destroy();
} catch (LifecycleException e1) {
log.debug("destroy() failed for failed Server ", e1);
}
return;
}
// Register shutdown hook
if (useShutdownHook) {
if (shutdownHook == null) {
shutdownHook = new CatalinaShutdownHook();
}
Runtime.getRuntime().addShutdownHook(shutdownHook);
}
if (await) {
await();
stop();
}
}
需要关注的就是CatalinaShutdownHook,Runtime.getRuntime().addShutdownHook的作用就是在JVM销毁前执行一个线程,这里也就是CatalinaShutdownHook,主要是用来做清理工作。
protected class CatalinaShutdownHook extends Thread {
@Override
public void run() {
try {
if (getServer() != null) {
Catalina.this.stop();
}
} catch (Throwable ex) {
...
}
}
}
具体实现类是StandardServer,是用来管理Service的,比较有意思的就是增加service的方式。Server内部使用了数组来存储Service。
@Override
public void addService(Service service) {
service.setServer(this);
synchronized (servicesLock) {
// 创建一个长度 +1 的新数组
Service results[] = new Service[services.length + 1];
// 将老的数据复制过去
System.arraycopy(services, 0, results, 0, services.length);
results[services.length] = service;
services = results;
// 启动 Service 组件
if (getState().isAvailable()) {
try {
service.start();
} catch (LifecycleException e) {
// Ignore
}
}
// 触发监听事件
support.firePropertyChange("service", null, service);
}
}
Service管理的崽崽有点多。看下定义:
public class StandardService extends LifecycleBase implements Service {
// 名字
private String name = null;
//Server 实例
private Server server = null;
// 连接器数组
protected Connector connectors[] = new Connector[0];
private final Object connectorsLock = new Object();
// 对应的 Engine 容器
private Engine engine = null;
// 映射器及其监听器
protected final Mapper mapper = new Mapper();
protected final MapperListener mapperListener = new MapperListener(this);
其中,MapperListener是为了支持热部署,当Web应用的部署发生变化时,Mapper中映射信息也要跟着变化,MapperListener就是一个监听器,监听变化,更新信息到Mapper中。
MapperListener比较简单,就是负责把信息喂给Mapper。事件监听用的还是LifeCycle。Mapper存的是映射信息,信息是从Host、Context、Wrapper里得到的。
在MapperListener中是有一个连环注册的:registerHost
、registerContext
、prepareWrapperMappingInfo
。
@Override
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())) {
// Registering the host will register the context and wrappers
registerHost(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);
}
}
// Default host may have changed
findDefaultHost();
}
private void registerContext(Context context) {
Host host = (Host)context.getParent();
WebResourceRoot resources = context.getResources();
String[] welcomeFiles = context.findWelcomeFiles();
List wrappers = new ArrayList<>();
for (Container container : context.findChildren()) {
prepareWrapperMappingInfo(context, (Wrapper) container, wrappers);
}
mapper.addContextVersion(host.getName(), host, contextPath,
context.getWebappVersion(), context, welcomeFiles, resources,
wrappers);
}
此外,Service中需要注意的就是各个组件的启动顺序。
protected void startInternal() throws LifecycleException {
//1. 触发启动监听器
setState(LifecycleState.STARTING);
//2. 先启动 Engine,Engine 会启动它子容器
if (engine != null) {
synchronized (engine) {
engine.start();
}
}
//3. 再启动 Mapper 监听器
mapperListener.start();
//4. 最后启动连接器,连接器会启动它子组件,比如 Endpoint
synchronized (connectorsLock) {
for (Connector connector: connectors) {
if (connector.getState() != LifecycleState.FAILED) {
connector.start();
}
}
}
}
Engine是顶层容器,对应的默认实现类是StandardEngine,继承了ContainerBase,并实现了Engine接口。其子容器是Host,持有一个Host容器的数组。ContainerBase中对子容器的存储和增删改查都提供了实现。
Engine自己要实现的部分:通过Valve实现将请求转发给子容器Host来处理。
每个容器组件都一个PipeLine,PipeLine中有一个基础阀(Basic Valve)
public StandardEngine() {
super();
pipeline.setBasic(new StandardEngineValve());
}
StandardEngineValve 的定义如下:
final class StandardEngineValve extends ValveBase {
public final void invoke(Request request, Response response)
throws IOException, ServletException {
// 拿到请求中的 Host 容器
Host host = request.getHost();
if (host == null) {
return;
}
// 调用 Host 容器中的 Pipeline 中的第一个 Valve
host.getPipeline().getFirst().invoke(request, response);
}
}
注意点:请求中的Host容器是因为,在请求到达Engine之前,Mapper组件已经对请求进行了路由处理,将容器对象保存到了请求对象中。
虽然看老师给的框架图中Mapper的位置,对上面这句话是没有疑异的,但是,好奇心和心虚让我特别想知道Mapper是咋做到的。然后对着代码看了篇详解:深入理解Tomcat(九)MapperListener和Mapper。写的很清楚,当然并不是看完了就学会怎么玩了……