一、Lifecycle
tomcat啟動,實際上就是對以上的組件進行實例化,因此使用Lifecycle接口統一管理各組件的生命周期,根據各個組件之間的父子級關系,首先調用init()方法逐級初始化各組件,然后在調用start()的方法進行啟動。
//初始化
public void init() throws LifecycleException; //啟動
public void start() throws LifecycleException; //停止
public void stop() throws LifecycleException; //銷毀
public void destroy() throws LifecycleException;
tomcat中的這些組件也會繼承Lifecycle,由子類再去實現這些方法。
二、startup.sh
os400=false
case "`uname`" in OS400*) os400=true;; esac # resolve links - $0 may be a softlink PRG="$0"
while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link"
else PRG=`dirname "$PRG"`/"$link" fi done PRGDIR=`dirname "$PRG"` EXECUTABLE=catalina.sh # Check that target executable exists if $os400; then # -x will Only work on the os400 if the files are: # 1. owned by the user # 2. owned by the PRIMARY group of the user # this will not work if the user belongs in secondary groups eval else
if [ ! -x "$PRGDIR"/"$EXECUTABLE" ]; then echo "Cannot find $PRGDIR/$EXECUTABLE" echo "The file is absent or does not have execute permission" echo "This file is needed to run this program" exit 1 fi fi exec "$PRGDIR"/"$EXECUTABLE" start "$@"
我們啟動tomcat的時候會使用startup.sh,看到shell腳本的最后一行,意思就是執行$EXECUTABLE變量(對應的是catalina.sh)並傳入參數start,之后就是執行java xxxx.jar org.apache.catalina.startup.Bootstrap start命令。
四、Bootstrap
private static volatile Bootstrap daemon = null; private static final Object daemonLock = new Object(); public static void main(String args[]) { synchronized (daemonLock) { if (daemon == null) { // Don't set daemon until init() has completed //實例化Bootstrap Bootstrap bootstrap = new Bootstrap(); try { //調用初始化方法 bootstrap.init(); } catch (Throwable t) { handleThrowable(t); t.printStackTrace(); return; } //賦值給daemon daemon = bootstrap; } else { 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")) { //tomcat啟動時傳入的值時start,因此啟動走此分支 daemon.setAwait(true); //加載初始化 daemon.load(args); //啟動 daemon.start(); 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); } }
init方法(Bootstrap)
public void init() throws Exception { //初始化類加載器
initClassLoaders(); Thread.currentThread().setContextClassLoader(catalinaLoader); SecurityClassLoad.securityClassLoad(catalinaLoader); // Load our startup class and call its process() method
if (log.isDebugEnabled()) { log.debug("Loading startup class"); } //實例化Catalina對象
Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina"); Object startupInstance = startupClass.getConstructor().newInstance(); // 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; //反射調用Catalina的setParentClassLoader方法
Method method = startupInstance.getClass().getMethod(methodName, paramTypes); method.invoke(startupInstance, paramValues); //賦值給catalinaDaemon
catalinaDaemon = startupInstance; }
load和start方法(Bootstrap)
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); } public void start() throws Exception { if (catalinaDaemon == null) { init(); } //反射調用Catalina的start方法
Method method = catalinaDaemon.getClass().getMethod("start", (Class [])null); method.invoke(catalinaDaemon, (Object [])null); }
五、Catalina
load方法
public void load() { if (loaded) { return; } loaded = true; long t1 = System.nanoTime(); initDirs(); // Before digester - it may be needed
initNaming(); //創建Digester對象,用於解析server.xml文件
Digester digester = createStartDigester(); InputSource inputSource = null; InputStream inputStream = null; File file = null; try { try { //定位到配置文件server.xml
file = configFile(); inputStream = new FileInputStream(file); inputSource = new InputSource(file.toURI().toURL().toString()); } catch (Exception e) { if (log.isDebugEnabled()) { log.debug(sm.getString("catalina.configFail", file), e); } } if (inputStream == null) { try { inputStream = getClass().getClassLoader() .getResourceAsStream(getConfigFile()); inputSource = new InputSource (getClass().getClassLoader() .getResource(getConfigFile()).toString()); } catch (Exception e) { if (log.isDebugEnabled()) { log.debug(sm.getString("catalina.configFail", getConfigFile()), 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 (log.isDebugEnabled()) { log.debug(sm.getString("catalina.configFail", "server-embed.xml"), e); } } } if (inputStream == null || inputSource == null) { if (file == null) { log.warn(sm.getString("catalina.configFail", getConfigFile() + "] or [server-embed.xml]")); } else { log.warn(sm.getString("catalina.configFail", file.getAbsolutePath())); if (file.exists() && !file.canRead()) { log.warn("Permissions incorrect, read permission is not allowed on the file."); } } return; } try { inputSource.setByteStream(inputStream); digester.push(this); //解析配置文件server.xml
digester.parse(inputSource); } catch (SAXParseException spe) { log.warn("Catalina.start using " + getConfigFile() + ": " + spe.getMessage()); return; } catch (Exception e) { log.warn("Catalina.start using " + getConfigFile() + ": " , e); return; } } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { // Ignore
} } } getServer().setCatalina(this); getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile()); getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile()); // Stream redirection
initStreams(); // Start the new server
try { //調用server對象的init方法
getServer().init(); } catch (LifecycleException e) { if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) { throw new java.lang.Error(e); } else { log.error("Catalina.start", e); } } long t2 = System.nanoTime(); if(log.isInfoEnabled()) { log.info("Initialization processed in " + ((t2 - t1) / 1000000) + " ms"); } } public Object parse(InputSource input) throws IOException, SAXException { configure(); getXMLReader().parse(input); //返回的root就是Catalina對象,並且實例化了Server(StandardServer對象,包含了server以下的service,connector等實例對象)賦值給Catalina的server屬性
return root; }
StandardServer繼承了LifecycleMBeanBase->LifecycleBase,因此調用server的init方法,就是調用LifecycleBase的init方法
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方法
initInternal(); setStateInternal(LifecycleState.INITIALIZED, null, false); } catch (Throwable t) { handleSubClassException(t, "lifecycleBase.initFail", toString()); } } //server容器初始化
protected void initInternal() throws LifecycleException { super.initInternal(); // Register global String cache // Note although the cache is global, if there are multiple Servers // present in the JVM (may happen when embedding) then the same cache // will be registered under multiple names
onameStringCache = register(new StringCache(), "type=StringCache"); // Register the MBeanFactory
MBeanFactory factory = new MBeanFactory(); factory.setContainer(this); onameMBeanFactory = register(factory, "type=MBeanFactory"); // Register the naming resources
globalNamingResources.init(); // Populate the extension validator with JARs from common and shared // class loaders
if (getCatalina() != null) { ClassLoader cl = getCatalina().getParentClassLoader(); // Walk the class loader hierarchy. Stop at the system class loader. // This will add the shared (if present) and common class loaders
while (cl != null && cl != ClassLoader.getSystemClassLoader()) { if (cl instanceof URLClassLoader) { URL[] urls = ((URLClassLoader) cl).getURLs(); for (URL url : urls) { if (url.getProtocol().equals("file")) { try { File f = new File (url.toURI()); if (f.isFile() && f.getName().endsWith(".jar")) { ExtensionValidator.addSystemResource(f); } } catch (URISyntaxException | IOException e) { // Ignore
} } } } cl = cl.getParent(); } } // Initialize our defined Services //初始化service容器
for (Service service : services) { //重復sever的init過程,只不過這次是調用StandardService的initInternal方法
service.init(); } }
service容器初始化
//service容器初始化
protected void initInternal() throws LifecycleException { super.initInternal(); if (engine != null) { //engine容器的初始化,調用StandardEngine的initInternal方法
engine.init(); } // Initialize any Executors
for (Executor executor : findExecutors()) { if (executor instanceof JmxEnabled) { ((JmxEnabled) executor).setDomain(getDomain()); } executor.init(); } // Initialize mapper listener
mapperListener.init(); // Initialize our defined Connectors
synchronized (connectorsLock) { for (Connector connector : connectors) { try { //連接器的初始化
connector.init(); } catch (Exception e) { String message = sm.getString( "standardService.connector.initFailed", connector); log.error(message, e); if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) { throw new LifecycleException(message); } } } } }
engine容器的初始化
//engine容器的初始化
protected void initInternal() throws LifecycleException { // Ensure that a Realm is present before any attempt is made to start // one. This will create the default NullRealm if necessary.
getRealm(); //調用父類ContainerBase的初始化方法
super.initInternal(); } //engine初始化創建了一個線程池,在engine組件start階段使用
protected void initInternal() throws LifecycleException { BlockingQueue<Runnable> startStopQueue = new LinkedBlockingQueue<>(); startStopExecutor = new ThreadPoolExecutor( getStartStopThreadsInternal(), getStartStopThreadsInternal(), 10, TimeUnit.SECONDS, startStopQueue, new StartStopThreadFactory(getName() + "-startStop-")); startStopExecutor.allowCoreThreadTimeOut(true); super.initInternal(); }
連接器Connector的初始化
protected void initInternal() throws LifecycleException { super.initInternal(); //適配器的初始化,為了完成請求HttpRequest到HttpServletRequest的轉換
adapter = new CoyoteAdapter(this); protocolHandler.setAdapter(adapter); // Make sure parseBodyMethodsSet has a default
if (null == parseBodyMethodsSet) { setParseBodyMethods(getParseBodyMethods()); } if (protocolHandler.isAprRequired() && !AprLifecycleListener.isInstanceCreated()) { throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoAprListener", getProtocolHandlerClassName())); } if (protocolHandler.isAprRequired() && !AprLifecycleListener.isAprAvailable()) { throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoAprLibrary", getProtocolHandlerClassName())); } if (AprLifecycleListener.isAprAvailable() && AprLifecycleListener.getUseOpenSSL() && protocolHandler instanceof AbstractHttp11JsseProtocol) { AbstractHttp11JsseProtocol<?> jsseProtocolHandler = (AbstractHttp11JsseProtocol<?>) protocolHandler; if (jsseProtocolHandler.isSSLEnabled() && jsseProtocolHandler.getSslImplementationName() == null) { // OpenSSL is compatible with the JSSE configuration, so use it if APR is available
jsseProtocolHandler.setSslImplementationName(OpenSSLImplementation.class.getName()); } } try { //協議處理器protocolHandler的初始化,主要是其內部Endpoint的初始化
protocolHandler.init(); } catch (Exception e) { throw new LifecycleException( sm.getString("coyoteConnector.protocolHandlerInitializationFailed"), e); } }
協議處理器protocolHandler初始化
public void init() throws Exception { // Upgrade protocols have to be configured first since the endpoint // init (triggered via super.init() below) uses this list to configure // the list of ALPN protocols to advertise
for (UpgradeProtocol upgradeProtocol : upgradeProtocols) { configureUpgradeProtocol(upgradeProtocol); } super.init(); // Set the Http11Protocol (i.e. this) for any upgrade protocols once // this has completed initialisation as the upgrade protocols may expect this // to be initialised when the call is made
for (UpgradeProtocol upgradeProtocol : upgradeProtocols) { if (upgradeProtocol instanceof Http2Protocol) { ((Http2Protocol) upgradeProtocol).setHttp11Protocol(this); } } } public void init() throws Exception { if (getLog().isInfoEnabled()) { getLog().info(sm.getString("abstractProtocolHandler.init", getName())); } if (oname == null) { // Component not pre-registered so register it
oname = createObjectName(); if (oname != null) { Registry.getRegistry(null, null).registerComponent(this, oname, null); } } if (this.domain != null) { ObjectName rgOname = new ObjectName(domain + ":type=GlobalRequestProcessor,name=" + getName()); this.rgOname = rgOname; Registry.getRegistry(null, null).registerComponent( getHandler().getGlobal(), rgOname, null); } String endpointName = getName(); endpoint.setName(endpointName.substring(1, endpointName.length()-1)); endpoint.setDomain(domain); //通信斷點的初始化
endpoint.init(); } //AbstractEndpoint
public void init() throws Exception { if (bindOnInit) { //重要
bind(); bindState = BindState.BOUND_ON_INIT; } if (this.domain != null) { // Register endpoint (as ThreadPool - historical name)
oname = new ObjectName(domain + ":type=ThreadPool,name=\"" + getName() + "\""); Registry.getRegistry(null, null).registerComponent(this, oname, null); ObjectName socketPropertiesOname = new ObjectName(domain +
":type=SocketProperties,name=\"" + getName() + "\""); socketProperties.setObjectName(socketPropertiesOname); Registry.getRegistry(null, null).registerComponent(socketProperties, socketPropertiesOname, null); for (SSLHostConfig sslHostConfig : findSslHostConfigs()) { registerJmx(sslHostConfig); } } } //NioEndpoint類
public void bind() throws Exception { if (!getUseInheritedChannel()) { //獲取nio通道channel,tomcat8之后默認就是nio
serverSock = ServerSocketChannel.open(); socketProperties.setProperties(serverSock.socket()); InetSocketAddress addr = (getAddress()!=null?new InetSocketAddress(getAddress(),getPort()):new InetSocketAddress(getPort())); //綁定端口,但尚未使用accept獲取客戶端連接
serverSock.socket().bind(addr,getAcceptCount()); } else { // Retrieve the channel provided by the OS
Channel ic = System.inheritedChannel(); if (ic instanceof ServerSocketChannel) { serverSock = (ServerSocketChannel) ic; } if (serverSock == null) { throw new IllegalArgumentException(sm.getString("endpoint.init.bind.inherited")); } } //設置為阻塞模式
serverSock.configureBlocking(true); //mimic APR behavior // Initialize thread count defaults for acceptor, poller
if (acceptorThreadCount == 0) { // FIXME: Doesn't seem to work that well with multiple accept threads
acceptorThreadCount = 1; } if (pollerThreadCount <= 0) { //minimum one poller thread
pollerThreadCount = 1; } setStopLatch(new CountDownLatch(pollerThreadCount)); // 初始化SSL
initialiseSsl(); //初始化BlockPoller線程並啟動 selectorPool.open(); }
start方法
public void start() { if (getServer() == null) { load(); } if (getServer() == null) { log.fatal("Cannot start server. Server instance is not configured."); return; } long t1 = System.nanoTime(); // Start the new server
try { //最終調用的是StandardServer的startInternal方法
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; } long t2 = System.nanoTime(); if(log.isInfoEnabled()) { log.info("Server startup in " + ((t2 - t1) / 1000000) + " ms"); } // Register shutdown hook
if (useShutdownHook) { if (shutdownHook == null) { shutdownHook = new CatalinaShutdownHook(); } Runtime.getRuntime().addShutdownHook(shutdownHook); // If JULI is being used, disable JULI's shutdown hook since // shutdown hooks run in parallel and log messages may be lost // if JULI's hook completes before the CatalinaShutdownHook()
LogManager logManager = LogManager.getLogManager(); if (logManager instanceof ClassLoaderLogManager) { ((ClassLoaderLogManager) logManager).setUseShutdownHook( false); } } if (await) { await(); stop(); } }
start方法采用的和init方法一樣的設計模式,因此也是調用各個組件的startInternal方法,完成啟動。
StandardServer的啟動
//StandardServer
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
service.start(); } } }
StandardService的啟動
//StandardService
protected void startInternal() throws LifecycleException { if(log.isInfoEnabled()) { log.info(sm.getString("standardService.start.name", this.name)); } setState(LifecycleState.STARTING); // Start our defined Container first
if (engine != null) { synchronized (engine) { //啟動engine
engine.start(); } } synchronized (executors) { for (Executor executor: executors) { executor.start(); } } mapperListener.start(); // Start our defined Connectors second
synchronized (connectorsLock) { for (Connector connector: connectors) { try { // If it has already failed, don't try and start it
if (connector.getState() != LifecycleState.FAILED) { //啟動connector
connector.start(); } } catch (Exception e) { log.error(sm.getString( "standardService.connector.startFailed", connector), e); } } } }
StandardEngine的啟動
//StandardEngine
protected synchronized void startInternal() throws LifecycleException { // Log our server identification information
if (log.isInfoEnabled()) { log.info(sm.getString("standardEngine.start", ServerInfo.getServerInfo())); } // Standard container startup
super.startInternal(); } //ContainerBase
protected synchronized void startInternal() throws LifecycleException { // Start our subordinate components, if any
logger = null; getLogger(); Cluster cluster = getClusterInternal(); if (cluster instanceof Lifecycle) { ((Lifecycle) cluster).start(); } Realm realm = getRealmInternal(); if (realm instanceof Lifecycle) { ((Lifecycle) realm).start(); } //查找子容器,啟動子容器,host在初始化階段后還是不完整的需要繼續封裝你,把容器關系維護完整
Container children[] = findChildren(); List<Future<Void>> results = new ArrayList<>(); for (Container child : children) {+-
//在init階段初始化的線程池,現在開始提交任務執行
results.add(startStopExecutor.submit(new StartChild(child))); } MultiThrowable multiThrowable = null; for (Future<Void> result : results) { try { result.get(); } catch (Throwable e) { log.error(sm.getString("containerBase.threadedStartFailed"), e); if (multiThrowable == null) { multiThrowable = new MultiThrowable(); } multiThrowable.add(e); } } if (multiThrowable != null) { throw new LifecycleException(sm.getString("containerBase.threadedStartFailed"), multiThrowable.getThrowable()); } // Start the Valves in our pipeline (including the basic), if any
if (pipeline instanceof Lifecycle) { ((Lifecycle) pipeline).start(); } //設置生命周期容器狀態
setState(LifecycleState.STARTING); // Start our thread
threadStart(); }
在init方法里,容器的初始化只執行到了Engine,剩下的容器初始化交給了在engine初始化方法里初始化的線程池來進行。進入ContainerBase的內部類StartChild的call方法,接着調用child.start(),最終調用StandardHost的startInternal方法。
//StandardHost
protected synchronized void startInternal() throws LifecycleException { // Set error report valve
String errorValve = getErrorReportValveClass(); if ((errorValve != null) && (!errorValve.equals(""))) { try { boolean found = false; Valve[] valves = getPipeline().getValves(); for (Valve valve : valves) { if (errorValve.equals(valve.getClass().getName())) { found = true; break; } } if(!found) { Valve valve = (Valve) Class.forName(errorValve).getConstructor().newInstance(); getPipeline().addValve(valve); } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString( "standardHost.invalidErrorReportValveClass", errorValve), t); } } //調用ContainerBase的startInternal方法
super.startInternal(); }
子線程再次進入ContainerBase的startInternal方法,這次findChildren()不會再次獲得子容器,會接着往下,執行setState(LifecycleState.STARTING)方法,設置生命周期狀態。
//LifecycleBase
protected synchronized void setState(LifecycleState state) throws LifecycleException { setStateInternal(state, null, true); } //LifecycleBase
private synchronized void setStateInternal(LifecycleState state, Object data, boolean check) throws LifecycleException { //省略代碼
··· this.state = state; String lifecycleEvent = state.getLifecycleEvent(); if (lifecycleEvent != null) { //觸發生命周期事件 fireLifecycleEvent(lifecycleEvent, data); } } //LifecycleBase
protected void fireLifecycleEvent(String type, Object data) { LifecycleEvent event = new LifecycleEvent(this, type, data); for (LifecycleListener listener : lifecycleListeners) { //往監聽器里添加事件
listener.lifecycleEvent(event); } }
Host的實例化,是通過設置生命周期狀態(start),通過觸發host的生命周期事件fireLifecycleEvent來執行后續(還會接着實例化host下面的容器:context等)的工作,在Hostconfig(生命周期監聽器)中完成。
//HostConfig
public void lifecycleEvent(LifecycleEvent event) { // Identify the host we are associated with
try { host = (Host) event.getLifecycle(); if (host instanceof StandardHost) { setCopyXML(((StandardHost) host).isCopyXML()); setDeployXML(((StandardHost) host).isDeployXML()); setUnpackWARs(((StandardHost) host).isUnpackWARs()); setContextClass(((StandardHost) host).getContextClass()); } } catch (ClassCastException e) { log.error(sm.getString("hostConfig.cce", event.getLifecycle()), e); return; } // Process the event that has occurred
if (event.getType().equals(Lifecycle.PERIODIC_EVENT)) { check(); } else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) { beforeStart(); } else if (event.getType().equals(Lifecycle.START_EVENT)) { //會執行此方法
start(); } else if (event.getType().equals(Lifecycle.STOP_EVENT)) { stop(); } } public void start() { ··· //部署app應用
if (host.getDeployOnStartup()) { deployApps(); } } //發布應用
protected void deployApps() { File appBase = host.getAppBaseFile(); File configBase = host.getConfigBaseFile(); String[] filteredAppPaths = filterAppPaths(appBase.list()); // XML描述的方式
deployDescriptors(configBase, configBase.list()); // WAR包的方式
deployWARs(appBase, filteredAppPaths); // 文件夾的方式
deployDirectories(appBase, filteredAppPaths); }
以文件夾的方式為例
protected void deployDirectories(File appBase, String[] files) { if (files == null) { return; } //創建了一個線程池
ExecutorService es = host.getStartStopExecutor(); List<Future<?>> results = new ArrayList<>(); for (String file : files) { if (file.equalsIgnoreCase("META-INF")) { continue; } if (file.equalsIgnoreCase("WEB-INF")) { continue; } File dir = new File(appBase, file); if (dir.isDirectory()) { ContextName cn = new ContextName(file, false); if (tryAddServiced(cn.getName())) { try { if (deploymentExists(cn.getName())) { removeServiced(cn.getName()); continue; } // 把context的創建和start以線程的方式提交
results.add(es.submit(new DeployDirectory(this, cn, dir))); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); removeServiced(cn.getName()); throw t; } } } } for (Future<?> result : results) { try { result.get(); } catch (Exception e) { log.error(sm.getString("hostConfig.deployDir.threaded.error"), e); } } } //DeployDirectory
public void run() { try { config.deployDirectory(cn, dir); } finally { config.removeServiced(cn.getName()); } } //HostConfig
protected void deployDirectory(ContextName cn, File dir) { ··· try { if (deployThisXML && xml.exists()) { synchronized (digesterLock) { try { //通過xml解析獲取Context對象
context = (Context) digester.parse(xml); } catch (Exception e) { log.error(sm.getString("hostConfig.deployDescriptor.error", xml), e); context = new FailedContext(); } finally { digester.reset(); if (context == null) { context = new FailedContext(); } } } if (copyThisXml == false && context instanceof StandardContext) { // Host is using default value. Context may override it.
copyThisXml = ((StandardContext) context).getCopyXML(); } if (copyThisXml) { Files.copy(xml.toPath(), xmlCopy.toPath()); context.setConfigFile(xmlCopy.toURI().toURL()); } else { context.setConfigFile(xml.toURI().toURL()); } } else if (!deployThisXML && xml.exists()) { // Block deployment as META-INF/context.xml may contain security // configuration necessary for a secure deployment.
log.error(sm.getString("hostConfig.deployDescriptor.blocked", cn.getPath(), xml, xmlCopy)); context = new FailedContext(); } else { context = (Context) Class.forName(contextClass).getConstructor().newInstance(); } Class<?> clazz = Class.forName(host.getConfigClass()); LifecycleListener listener = (LifecycleListener) clazz.getConstructor().newInstance(); context.addLifecycleListener(listener); context.setName(cn.getName()); context.setPath(cn.getPath()); context.setWebappVersion(cn.getVersion()); context.setDocBase(cn.getBaseName()); //添加到host容器中,此時context還是不完整的,需要進一步封裝wrapper(servlet)
host.addChild(context); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString("hostConfig.deployDir.error", dir.getAbsolutePath()), t); } finally { ··· } deployed.put(cn.getName(), deployedApp); if( log.isInfoEnabled() ) { log.info(sm.getString("hostConfig.deployDir.finished", dir.getAbsolutePath(), Long.valueOf(System.currentTimeMillis() - startTime))); } }
host.addChild(context)時才觸發context實例核心內容
//StandardHost
public void addChild(Container child) { ··· //調用父類
super.addChild(child); } //ContainerBase
public void addChild(Container child) { if (Globals.IS_SECURITY_ENABLED) { PrivilegedAction<Void> dp =
new PrivilegedAddChild(child); AccessController.doPrivileged(dp); } else { addChildInternal(child); } } private void addChildInternal(Container child) { ··· // Start child // Don't do this inside sync block - start can be a slow process and // locking the children object can cause problems elsewhere
try { if ((getState().isAvailable() || LifecycleState.STARTING_PREP.equals(getState())) && startChildren) { //這個child就是StandardContext,接着依然通過父類調用到StandardContext的startInternal方法
child.start(); } } catch (LifecycleException e) { log.error("ContainerBase.addChild: start: ", e); throw new IllegalStateException(sm.getString("containerBase.child.start"), e); } finally { fireContainerEvent(ADD_CHILD_EVENT, child); } }
context具體讀取web.xml封裝wrapper過程也是使用了事件驅動機制,往監聽器添加了一個事件,交給ContextConfig執行。
protected synchronized void startInternal() throws LifecycleException { ··· // 創建工作目錄,tomcat下的work目錄
postWorkDirectory(); ··· if (getLoader() == null) { //web應用類加載器,每個Context都會設置一個
WebappLoader webappLoader = new WebappLoader(); webappLoader.setDelegate(getDelegate()); setLoader(webappLoader); } ··· // 發出生命周期事件,調度了ContextConfig,讀取web.xml,這里就是讀取某一個項目的web.xml內容
fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null); ··· // 加載初始化servlet(只是加載了servlet的全限定類名)
if (ok) { //loadOnStartup才開始根據servlet的全限定類名初始化servlet
if (!loadOnStartup(findChildren())){ log.error(sm.getString("standardContext.servletFail")); ok = false; } } ··· } public boolean loadOnStartup(Container children[]) { ··· // Load the collected "load on startup" servlets
for (ArrayList<Wrapper> list : map.values()) { for (Wrapper wrapper : list) { try { //實例化servlet
wrapper.load(); } catch (ServletException e) { getLogger().error(sm.getString("standardContext.loadOnStartup.loadException", getName(), wrapper.getName()), StandardWrapper.getRootCause(e)); // NOTE: load errors (including a servlet that throws // UnavailableException from the init() method) are NOT // fatal to application startup // unless failCtxIfServletStartFails="true" is specified
if(getComputedFailCtxIfServletStartFails()) { return false; } } } } return true; } public synchronized void load() throws ServletException { //反射獲取了servlet的實例
instance = loadServlet(); ··· }
Connector的啟動,在StandardService的啟動的時候先啟動的Engine,然后遍歷調用connector.start(),啟動connector。
protected void startInternal() throws LifecycleException { // Validate settings before starting if (getPort() < 0) { throw new LifecycleException(sm.getString( "coyoteConnector.invalidPort", Integer.valueOf(getPort()))); } setState(LifecycleState.STARTING); try { //關鍵點,協議處理器的啟動 protocolHandler.start(); } catch (Exception e) { throw new LifecycleException( sm.getString("coyoteConnector.protocolHandlerStartFailed"), e); } } public void start() throws Exception { if (getLog().isInfoEnabled()) { getLog().info(sm.getString("abstractProtocolHandler.start", getName())); } //啟動endpiont endpoint.start(); // Start timeout thread asyncTimeout = new AsyncTimeout(); Thread timeoutThread = new Thread(asyncTimeout, getNameInternal() + "-AsyncTimeout"); int priority = endpoint.getThreadPriority(); if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) { priority = Thread.NORM_PRIORITY; } timeoutThread.setPriority(priority); timeoutThread.setDaemon(true); timeoutThread.start(); } public final void start() throws Exception { if (bindState == BindState.UNBOUND) { bind(); bindState = BindState.BOUND_ON_START; } startInternal(); } //NioEndpoint public void startInternal() throws Exception { if (!running) { running = true; paused = false; processorCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE, socketProperties.getProcessorCache()); eventCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE, socketProperties.getEventCache()); nioChannels = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE, socketProperties.getBufferPool()); // Create worker collection if (getExecutor() == null) { createExecutor(); } initializeConnectionLatch(); // NIO模型 創建poller線程並啟動 pollers = new Poller[getPollerThreadCount()]; for (int i=0; i<pollers.length; i++) { pollers[i] = new Poller(); Thread pollerThread = new Thread(pollers[i], getName() + "-ClientPoller-"+i); pollerThread.setPriority(threadPriority); pollerThread.setDaemon(true); pollerThread.start(); } //啟動acceptor線程 startAcceptorThreads(); } } protected final void startAcceptorThreads() { int count = getAcceptorThreadCount(); acceptors = new Acceptor[count]; for (int i = 0; i < count; i++) { acceptors[i] = createAcceptor(); String threadName = getName() + "-Acceptor-" + i; acceptors[i].setThreadName(threadName); Thread t = new Thread(acceptors[i], threadName); t.setPriority(getAcceptorThreadPriority()); t.setDaemon(getDaemon()); t.start(); } }
啟動acceptor線程
public class NioEndpoint extends AbstractJsseEndpoint<NioChannel> { private volatile ServerSocketChannel serverSock = null; protected class Acceptor extends AbstractEndpoint.Acceptor { @Override public void run() { int errorDelay = 0; // Loop until we receive a shutdown command
while (running) { // Loop if endpoint is paused
while (paused && running) { state = AcceptorState.PAUSED; try { Thread.sleep(50); } catch (InterruptedException e) { // Ignore
} } if (!running) { break; } state = AcceptorState.RUNNING; try { //if we have reached max connections, wait
countUpOrAwaitConnection(); SocketChannel socket = null; try { // 獲取socket連接
socket = serverSock.accept(); } catch (IOException ioe) { ··· } ··· } catch (Throwable t) { ··· } } state = AcceptorState.ENDED; } ··· } }
到此,tomecat的初始化工作就完成了,Acceptor線程會阻塞在socket = serverSock.accept()方法上,等待客戶端的連接。