Primeiro, o processo principal de inicialização do Tomcat
Apresentei a você o design do ciclo de vida no Tomcat. Dominar isso é muito útil para analisarmos o processo central do Tomcat, ou seja, precisamos criar componentes centrais relacionados, como Server e Service. cycle method.
1. Inicie a entrada
Você pode iniciar o serviço do Tomcat por meio de um script (startup.bat), mas se você observar os comandos do script, verá que o método principal no Bootstrap é finalmente chamado, portanto, precisamos iniciar pelo método principal
Então nós olhamos para o código no método principal, existem três métodos que precisamos focar
- método bootstrap.init()
- método load()
- método start()
Ou seja, as operações principais do Tomcat serão concluídas nesses três métodos.
2. método de inicialização
Vamos dar uma olhada no código no método init, apenas removemos os não essenciais
public void init() throws Exception {
// 创建相关的类加载器
initClassLoaders();
// 省略部分代码...
// 通过反射创建了 Catalina 类对象
Class<?> startupClass = catalinaLoader
.loadClass("org.apache.catalina.startup.Catalina");
// 创建了 Catalina 实例
Object startupInstance = startupClass.getConstructor().newInstance();
// 省略部分代码...
String methodName = "setParentClassLoader";
Class<?> paramTypes[] = new Class[1];
paramTypes[0] = Class.forName("java.lang.ClassLoader");
Object paramValues[] = new Object[1];
paramValues[0] = sharedLoader;
// 把 sharedLoader 设置为了 commonLoader的父加载器
Method method =
startupInstance.getClass().getMethod(methodName, paramTypes);
method.invoke(startupInstance, paramValues);
// Catalina 实例 赋值给了 catalinaDaemon
catalinaDaemon = startupInstance;
}
复制代码
- A primeira é chamar o método initClassLoaders(). Este método irá completar a criação do ClassLoader correspondente. Isso é mais importante. Vou escrever um artigo para apresentá-lo mais tarde.
- Crie um objeto de classe Catalina por meio de reflexão e crie uma instância de Catalina por meio de reflexão
- O relacionamento pai-filho do carregador de classes está definido
- Usamos a variável de membro catalinaDaemon para registrar a instância Catalina que criamos
Esta é uma informação útil que podemos obter através do método bootstrap.init(). Então continuamos a olhar abaixo.
3. método de carregamento
Então vamos ver o que o método load faz. O código é o seguinte:
private void load(String[] arguments) throws Exception {
// Call the load() method
String methodName = "load"; // 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;
}
// catalinaDaemon 就是在 init中创建的 Catalina 对象
Method method =
catalinaDaemon.getClass().getMethod(methodName, paramTypes);
if (log.isDebugEnabled()) {
log.debug("Calling startup class " + method);
}
// 会执行 Catalina的load方法
method.invoke(catalinaDaemon, param);
}
复制代码
O código acima é bem simples, e também podemos ver que a função desse método é chamar o método load da Catalina comentando. Então também precisamos adicioná-lo ao método load da Catalina para visualizar, o código também é relativamente longo, deixando apenas o código da chave
public void load() {
if (loaded) {
return; // 只能被加载一次
}
loaded = true;
initDirs(); // 废弃的方法
// Before digester - it may be needed
initNaming(); // 和JNDI 相关的内容 忽略
// Create and execute our Digester
// 创建并且执行我们的 Digester 对象 Server.xml
Digester digester = createStartDigester();
// 省略掉了 Digester文件处理的代码
getServer().setCatalina(this); // Server对象绑定 Catalina对象
getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());
// Stream redirection
initStreams();
// 省略掉了部分代码...
getServer().init(); // 完成 Server Service Engine Connector等组件的init操作
}
复制代码
Depois de simplificar o código acima, descobrimos que o método Load é bem simples e faz duas coisas.
- A análise do arquivo Server.xml é concluída através do componente Digester no Apache
- A inicialização dos componentes principais, como Servidor, Serviço, Engin e Conector, é concluída por meio do método getServer().init(), que ecoa o LifecycleBase anterior.
Se o conteúdo do ciclo de vida não estiver claro, consulte a introdução do conteúdo anterior
4. método de início
Finalmente, vamos ver o código do método start.
public void start() throws Exception {
if (catalinaDaemon == null) {
init(); // 如果 catalinaDaemon 为空 初始化操作
}
// 获取的是 Catalina 中的 start方法
Method method = catalinaDaemon.getClass().getMethod("start", (Class [])null);
// 执行 Catalina 的start方法
method.invoke(catalinaDaemon, (Object [])null);
}
复制代码
A lógica do código acima também é bem clara, ou seja, o método start do objeto Catalina é chamado por reflexão. Então vá para o método start da Catalina para verificar.
public void start() {
if (getServer() == null) {
load(); // 如果Server 为空 重新 init 相关的组件
}
if (getServer() == null) {
log.fatal("Cannot start server. Server instance is not configured.");
return;
}
// Start the new server 关键方法--->启动Server
try {
getServer().start();
} catch (LifecycleException e) {
// 省略...
}
// 省略...
// Register shutdown hook 注册关闭的钩子
if (useShutdownHook) {
// 省略...
}
if (await) {
await();
stop();
}
}
复制代码
Através do código acima, podemos descobrir que o código central ainda é o método getServer.start(), ou seja, o método start da anotação relacionada é chamado aninhado através do objeto Server.
5. Resumo do processo principal
Podemos resumir o processo central de inicialização do Tomcat através da figura a seguir
A partir da figura, podemos ver que o Bootstrap não faz as coisas principais, e é feito principalmente pela Catalina.
Trabalhem juntos para criar e crescer juntos! Este é o 20º dia da minha participação no "Nuggets Daily New Plan · August Update Challenge", clique para ver os detalhes do evento .