目录
概述
tomcat 启动 大致流程
Server
StandardServer
利用8005端口关闭tomcat
总结
概述
了解一个程序,一定要知道他是干什么的,以及内部架构如何支撑这么干的,以及牵扯的到的概念、模式等知识点的解析(这里只介绍组件)。
Tomcat是Apache 开发的Web 应用服务器,支持最新的Servlet 和JSP 规范,servlet jsp是 J2EE里的规范。
学习tomcat组件,有助于指定tomcat启动的流程以及初始化的时候做了哪些工作,为后续请求和响应做准备。
组件从配置的地方来看比较好理解,tomcat核心配置文件是/config/server.xml
,如果对配置了解不足,就无法对组件进行探讨。
源码版本:apache-tomcat-8.5.84-src
下载地址:https://dlcdn.apache.org/tomcat/tomcat-8/v8.5.84/src/apache-tomcat-8.5.84-src.zip
tomcat 启动 大致流程
一图胜千言,先不管为啥,先看启动过程
Server
一个Server 就是一个tomcat,一个tomcat实例只能有一个server
其中 8005是tomcat监听关闭的端口号,如果socket监听到接受到了字符串SHUTDOWN
,则关闭tomcat具体实现类是StandardServer
,它内部包含多个Service,代码体现:
private Service services[] = new Service[0];//多个
StandardServer
分析到这里,可知当前类代表了Server组件,那么tomcat启动的时候做了哪些初始化工作?,先不去分析复杂代码,以及继承类,看主要工作(功能):
启动时调用流程:initInternal()
、startInternal()
- addService() 添加子组件,把子组件(web服务)添加到 services 变量中
- initInternal(),代码如下,忽略其他,可以看到主要是循环调用service的init,这个也可以在上面流程图中有体现
@Override
protected void initInternal() throws LifecycleException {
super.initInternal();
//...忽略的代码
// Initialize our defined Services
for (Service service : services) {
service.init();
}
}
- startInternal()
protected void startInternal() throws LifecycleException {
fireLifecycleEvent(CONFIGURE_START_EVENT, null);
setState(LifecycleState.STARTING);
globalNamingResources.start();
// Start our defined Services
synchronized (servicesLock) {
for (Service service : services) {
service.start();
}
}
}
可以看出主要其调用了 service组件的start()
方法
- destroyInternal() 销毁每个 service
- await() 这个很重要,主要是监听8005,如果返回,也就是下面代码中接收到 SHOTDOWN后break,tomcat会停止
public void await() {
...
// Set up a server socket to wait on
try {
awaitSocket = new ServerSocket(getPortWithOffset(), 1,
InetAddress.getByName(address));//创建 socket 监听:8005
} catch (IOException e) {
log.error(sm.getString("standardServer.awaitSocket.fail", address,
String.valueOf(getPortWithOffset()), String.valueOf(getPort()),
String.valueOf(getPortOffset())), e);
return;
}
try {
awaitThread = Thread.currentThread();
// Loop waiting for a connection and a valid command
while (!stopAwait) {
ServerSocket serverSocket = awaitSocket;
if (serverSocket == null) {
break;
}
// Wait for the next connection
Socket socket = null;
StringBuilder command = new StringBuilder();
try {
InputStream stream;
long acceptStartTime = System.currentTimeMillis();
try {
socket = serverSocket.accept();//阻塞
socket.setSoTimeout(10 * 1000); // Ten seconds
stream = socket.getInputStream();
} catch (SocketTimeoutException ste) {
continue;
} catch (AccessControlException ace) {
continue;
} catch (IOException e) {
if (stopAwait) {
break;
}
break;
}
// Read a set of characters from the socket
//这一堆代码就是解析 上边 stream 接受到的内容,放到 变量 command 中
// Match against our command string
boolean match = command.toString().equals(shutdown); //就是 SHUTDOWN
if (match)
//如果是停止服务命令"" 就退出服务
log.info(sm.getString("standardServer.shutdownViaPort"));
break;
} else {
log.warn(sm.getString("standardServer.invalidShutdownCommand", command.toString()));
}
}
}
利用8005端口关闭tomcat
使用telnet命令关闭,可百度window如何开启和使用,所以8005是绝不能外网开放的
//cmd
telnet localhost 8005
此时会链接成功 弹出新窗口,直接输入 SHUTDOWN
如下8005端口接受到SHUTDOWN
命令,跳出阻塞,往下执行,后续就是停止tomcat的方法
总结
Server组件是在初始化的时候被Catalina load方法调用,后续开启的组件调用链。当前类主要是socket监听8005端口,一旦接受到SHUTDOWN 就会停止tomcat的运行,所以8005不要对外网开放。