tomcat源码分析(一)
2024-08-27 09:57:03
tomcat的启动从Bootstrap类的main方法开始。
public static void main(String args[]) { //单例
if (daemon == null) {
daemon = new Bootstrap();//实例化Bootstrap对象
try {
//实例化Catalina 并装载3个classloader,设置Catalina的父加载器
daemon.init();
} catch (Throwable t) {
t.printStackTrace();
return;
}
} try {
String command = "start";
if (args.length > 0) {
command = args[args.length - 1];
} if (command.equals("startd")) {
args[0] = "start";
daemon.load(args);
daemon.start();
} else if (command.equals("stopd")) {
args[0] = "stop";
daemon.stop();
} else if (command.equals("start")) {
daemon.setAwait(true);
daemon.load(args);//加载
daemon.start();//启动
} else if (command.equals("stop")) {
daemon.stopServer(args);
} else {
log.warn("Bootstrap: command \"" + command + "\" does not exist.");
}
} catch (Throwable t) {
t.printStackTrace();
} }
/**
* 一些初始化工作 初始化一个守护线程
* Initialize daemon.
*/
public void init()
throws Exception
{ // Set Catalina path 初始化Tomcat的安装路径 home\base
setCatalinaHome();
setCatalinaBase(); initClassLoaders();//初始化变量classloader:catalinaloader、commonloader、sharedloader 三个加载器 Thread.currentThread().setContextClassLoader(catalinaLoader);//设置上下文的类加载器 SecurityClassLoad.securityClassLoad(catalinaLoader); // Load our startup class and call its process() method
if (log.isDebugEnabled())
log.debug("Loading startup class");
Class startupClass =
catalinaLoader.loadClass
("org.apache.catalina.startup.Catalina");
Object startupInstance = startupClass.newInstance();//得到了Catalina的实例 // Set the shared extensions class loader
if (log.isDebugEnabled())
log.debug("Setting startup class properties");
String methodName = "setParentClassLoader";//方法名
Class paramTypes[] = new Class[1];
paramTypes[0] = Class.forName("java.lang.ClassLoader");
Object paramValues[] = new Object[1];
paramValues[0] = sharedLoader;
Method method =
startupInstance.getClass().getMethod(methodName, paramTypes);//方法名、参数类型
method.invoke(startupInstance, paramValues);//利用反射调用Catalina的setParentClassLoader方法 设置共享扩展类装入器 catalinaDaemon = startupInstance; //赋值给Catalina的成员变量。
}
private void load(String[] arguments)
throws Exception { // Call the load() method
String methodName = "load";
Object param[];
Class paramTypes[];
if (arguments==null || arguments.length==0) {
paramTypes = null;
param = null;
} else {
paramTypes = new Class[1];
paramTypes[0] = arguments.getClass();
param = new Object[1];
param[0] = arguments;
}
Method method =
catalinaDaemon.getClass().getMethod(methodName, paramTypes);
if (log.isDebugEnabled())
log.debug("Calling startup class " + method);//利用反射调用Catalina的load()方法
method.invoke(catalinaDaemon, param); }
Catalina的load方法。主要是解析conf下的service.xml文件
public void load() { long t1 = System.nanoTime(); initDirs();//System.setPropertity("catalina.home")和catalina.home 设置系统目录 // Before digester - it may be needed initNaming();//设置propertity naming // Create and execute our Digester
Digester digester = createStartDigester(); InputSource inputSource = null;
InputStream inputStream = null;
File file = null;
try {
file = configFile();//读取con/server.xml的配置文件
inputStream = new FileInputStream(file);
inputSource = new InputSource("file://" + file.getAbsolutePath());
} catch (Exception e) {
;
}
if (inputStream == null) {
try {
inputStream = getClass().getClassLoader()
.getResourceAsStream(getConfigFile());
inputSource = new InputSource
(getClass().getClassLoader()
.getResource(getConfigFile()).toString());
} catch (Exception e) {
;
}
} // This should be included in catalina.jar
// Alternative: don't bother with xml, just create it manually.
if( inputStream==null ) {
try {
inputStream = getClass().getClassLoader()
.getResourceAsStream("server-embed.xml");
inputSource = new InputSource
(getClass().getClassLoader()
.getResource("server-embed.xml").toString());
} catch (Exception e) {
;
}
} if ((inputStream == null) && (file != null)) {
log.warn("Can't load server.xml from " + file.getAbsolutePath());
return;
} try {
inputSource.setByteStream(inputStream);
digester.push(this);
digester.parse(inputSource);//解析service.xml配置文件
inputStream.close();
} catch (Exception e) {
log.warn("Catalina.start using "
+ getConfigFile() + ": " , e);
return;
} // Stream redirection
initStreams(); // Start the new server
if (server instanceof Lifecycle) {
try {
server.initialize();
} catch (LifecycleException e) {
log.error("Catalina.start", e);
}
} long t2 = System.nanoTime();
if(log.isInfoEnabled())
log.info("Initialization processed in " + ((t2 - t1) / 1000000) + " ms"); }
tomcat从Catalina的start方法开启了。
public void start() { if (server == null) {
load();
} long t1 = System.nanoTime(); // Start the new server
if (server instanceof Lifecycle) {
try {
((Lifecycle) server).start();//这里的server是StandardService,在这里启动服务。
} catch (LifecycleException e) {
log.error("Catalina.start: ", e);
}
} long t2 = System.nanoTime();
if(log.isInfoEnabled())
log.info("Server startup in " + ((t2 - t1) / 1000000) + " ms"); try {
// Register shutdown hook
if (useShutdownHook) {
if (shutdownHook == null) {
shutdownHook = new CatalinaShutdownHook();
}
Runtime.getRuntime().addShutdownHook(shutdownHook);
}
} catch (Throwable t) {
// This will fail on JDK 1.2. Ignoring, as Tomcat can run
// fine without the shutdown hook.
} if (await) {
await();
stop();
} }
启动完成后,等待客户端的链接。
public void await() { server.await(); }
建立Socket,等待客户端的链接
public void await() {
// Negative values - don't wait on port - tomcat is embedded or we just don't like ports
if( port == -2 ) {
// undocumented yet - for embedding apps that are around, alive.
return;
}
if( port==-1 ) {
while( true ) {
try {
Thread.sleep( 10000 );
} catch( InterruptedException ex ) {
}
if( stopAwait ) return;
}
} // Set up a server socket to wait on
ServerSocket serverSocket = null;
try {
serverSocket =
new ServerSocket(port, 1,
InetAddress.getByName("localhost"));//创建了服务端Socket,绑定了localhost/127.0.0.1地址,端口号是8005
} catch (IOException e) {
log.error("StandardServer.await: create[" + port
+ "]: ", e);
System.exit(1);
} // Loop waiting for a connection and a valid command
while (true) {
//循环等待客户端连接
// Wait for the next connection
Socket socket = null;
InputStream stream = null;
try {
socket = serverSocket.accept();//启动完成了,在等待客户端的链接
socket.setSoTimeout(10 * 1000); // Ten seconds
stream = socket.getInputStream();//得到socket的输入流
} catch (AccessControlException ace) {
log.warn("StandardServer.accept security exception: "
+ ace.getMessage(), ace);
continue;
} catch (IOException e) {
log.error("StandardServer.await: accept: ", e);
System.exit(1);
} // Read a set of characters from the socket
StringBuffer command = new StringBuffer();
int expected = 1024; // Cut off to avoid DoS attack
while (expected < shutdown.length()) {
if (random == null)
random = new Random();
expected += (random.nextInt() % 1024);
}
while (expected > 0) {
int ch = -1;
try {
ch = stream.read();//读取流中的数据
} catch (IOException e) {
log.warn("StandardServer.await: read: ", e);
ch = -1;
}
if (ch < 32) // Control character or EOF terminates loop
break;
command.append((char) ch);//将数据添加到stringbuffer中
expected--;
} // Close the socket now that we are done with it
try {
socket.close();
} catch (IOException e) {
;
} // Match against our command string
boolean match = command.toString().equals(shutdown);//判断是否关闭应用
if (match) {
break;
} else
log.warn("StandardServer.await: Invalid command '" +
command.toString() + "' received"); } // Close the server socket and return
try {
serverSocket.close();//退出循环,关闭服务端socket
} catch (IOException e) {
;
} }
最新文章
- ztree
- SQL递归
- 完成端口CreateIoCompletionPort编写高性能的网络模型程序
- jsp&;servlet学习笔记
- PYTHON实现HTTP摘要认证(DIGEST AUTHENTICATION)
- 动手实践:在Windows上安装NumPy、Matplotlib、SciPy和IPython
- 【转】【教程】office 2013 &; visio 2013的激活
- 【Xilinx-VDMA模块学习】-01- VDMA IP的GUI配置介绍
- SQLite 之 C#版 System.Data.SQLite 使用
- JFreeChart与AJAX+JSON+ECharts两种处理方式生成热词统计可视化图表
- java 实现递归实现tree
- 彻底征服 Spring AOP 之 实战篇
- Unity3D中的生命周期函数
- SharePoint 2013 workflows stop working (Failed on started.)
- Windows下同一台机器上elasticsearch集群的配置以及elasticsearch-head插件的使用
- 测试用例Excel模板For Quality Center
- opencv——Rect和RotatedRect类详解
- C++获取private的变量-偷走private
- BZOJ 3190 赛车 | 计算几何
- Objective-C代码学习大纲(4)