Tomcat学习小记(二)
1、Tomcat源码入口
生命周期统一管理接口:LifeCycle
实现LifeCycle接口的类:(idea快捷键:Ctrl+h)
多个组件共同实现LifeCycle接口
Tomcat启动入口分析:
(1)根据不同的操作系统,找到启动脚本,startup.bat/startup.sh,我用的是windows操作系统,用的是startup.bat
startup.bat脚本最后执行函数,执行一个EXECUTABLE变量代表的函数(通过startup.bat去调用catalina.bat脚本),并向函数中传入start参数
(2)catalina.bat脚本中搜索传入的参数"start"
可以看到要去执行dostart函数,最后找到tomcat是由org.apache.catalina.startup.Bootstrap.main()启动的
CATALINA_BASE: D:\Tomcat\apache-tomcat-8.5.9 CATALINA_HOME: D:\Tomcat\apache-tomcat-8.5.9 Command line argument: -Djava.util.logging.config.file=D:\Tomcat\apache-tomcat-8.5.9\conf\logging.properties Command line argument: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager Command line argument: -Djdk.tls.ephemeralDHKeySize=2048 Command line argument: -Djava.protocol.handler.pkgs=org.apache.catalina.webresources Command line argument: -Dcatalina.base=D:\Tomcat\apache-tomcat-8.5.9 Command line argument: -Dcatalina.home=D:\Tomcat\apache-tomcat-8.5.9 Command line argument: -Djava.io.tmpdir=D:\Tomcat\apache-tomcat-8.5.9\temp
(3)启动类BootStrap,加载初始化以及启动
public static void main(String args[]) { synchronized (daemonLock) { if (daemon == null) { // Don't set daemon until init() has completed Bootstrap bootstrap = new Bootstrap(); try { bootstrap.init();//初始化 } catch (Throwable t) { handleThrowable(t); t.printStackTrace(); return; } daemon = bootstrap;//对象赋值 } else { // When running as a service the call to stop will be on a new // thread so make sure the correct class loader is used to // prevent a range of class not found exceptions. Thread.currentThread().setContextClassLoader(daemon.catalinaLoader); } } try { String command = "start"; if (args.length > 0) { command = args[args.length - 1]; } if (command.equals("startd")) { args[args.length - 1] = "start"; daemon.load(args); daemon.start(); } else if (command.equals("stopd")) { args[args.length - 1] = "stop"; daemon.stop(); } else if (command.equals("start")) { daemon.setAwait(true); daemon.load(args);//加载初始化,一级一级初始化(对象的实例),connector组件endpoint(socket通信端口bind,尚未accept) daemon.start();//启动,一级一级启动(开始accept接收请求) if (null == daemon.getServer()) { System.exit(1); } } else if (command.equals("stop")) { daemon.stopServer(args); } else if (command.equals("configtest")) { daemon.load(args); if (null == daemon.getServer()) { System.exit(1); } System.exit(0); } else { log.warn("Bootstrap: command \"" + command + "\" does not exist."); } } catch (Throwable t) { // Unwrap the Exception for clearer error reporting if (t instanceof InvocationTargetException && t.getCause() != null) { t = t.getCause(); } handleThrowable(t); t.printStackTrace(); System.exit(1); } }
2、Tomcat初始化
daemon.load(args);//加载初始化,一级一级初始化(对象的实例),connector组件endpoint(socket通信端口bind,尚未accept)
通过load方法通过反射调用catalina.load()方法
catalina.load()方法中调用digester.parse(inputSource)去解析server.xml文件
通过得到的server对象调用init()方法去初始化
init()方法实现LifecycleBase接口的init()方法,LifecycleBase接口的init()方法去调用LifecycleBase.initInternal()方法,而LifecycleBase.initInternal()方法是一个抽象方法,所以具体实现都是在子类中
//使用了模板方法设计模式,在父类中规定执行的步骤,而其中的某些步骤的实现都是在子类中实现
@Override public final synchronized void init() throws LifecycleException { if (!state.equals(LifecycleState.NEW)) { invalidTransition(Lifecycle.BEFORE_INIT_EVENT); } try { setStateInternal(LifecycleState.INITIALIZING, null, false);
//init关键之处,实现子类是standardServer类中 initInternal(); setStateInternal(LifecycleState.INITIALIZED, null, false); } catch (Throwable t) { handleSubClassException(t, "lifecycleBase.initFail", toString()); } }
standardServer.initInternal()子类中递归调用StandardService.init()方法,对servlet容器和连接器组件进行初始化,后续组件一级一级循环调用,一级一级进行初始化,逻辑相同
for (int i = 0; i < services.length; i++) { services[i].init(); }
3、Tomcat启动
启动流程和初始化相似
4、Servlet请求分析
servlet请求——>找到处理servlet实例——>servlet.service()
connect组件接收servlet请求,并传递到servlet容器中——>Engine引擎根据url找到处理servlet的实例
5、Servlet请求处理步骤
请求入口类:NioEndpoint类
NioEndpoint.Poller(),检查是否有可以被处理的socket请求
NioEndpoint.startAcceptorThreads(),用来接收请求的线程