Bootstrap#load()
daemon.load(args) 呼叫的, 其實就是 bootstrap.load(args)
main方法中執行了 daemon = bootstrap;
org.apache.catalina.startup.Bootstrap#load():
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; } // 拿到 Catalina 的 load 方法 Method method = catalinaDaemon.getClass().getMethod(methodName, paramTypes); if (log.isDebugEnabled()) { log.debug("Calling startup class " + method); } // 呼叫 Catalina#load(args)方法, 最侄訓呼叫Catalina#load() 方法 method.invoke(catalinaDaemon, param); }
反射呼叫了 Catalina.load(args)方法. 然后在方法中對args做了個驗證, 最終呼叫的,是 Catalina.load() 無參方法.
Catalina#load()
//org.apache.catalina.startup.Catalina#load() public void load() { if (loaded) { return; } loaded = true; //獲取當前納秒數, 1納秒=0.00000 0001秒 long t1 = System.nanoTime(); //初始化目錄 - 過時方法, 內部為空 initDirs(); //初始化 jmx 的環境變數 initNaming(); // Create and execute our Digester //創建決議器, 用于決議 conf/Server.xml 檔案,告訴Digester哪個xml標簽應該決議成什么類 Digester digester = createStartDigester(); InputSource inputSource = null; InputStream inputStream = null; File file = null; try { try { //file -> conf/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); } } //region conf/Server.xml檔案不存在時的處理 ...... //endregion try { inputSource.setByteStream(inputStream); //把 Catalina 作為一個頂級實體 digester.push(this); //決議 conf/server.xml 檔案 //決議程序中, 會實體化各個組件, 如 Server Container Connector等 digester.parse(inputSource); } catch (SAXParseException spe) { ...... } catch (Exception e) { ...... } } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { // Ignore } } } //決議Server.xml的時候, 會創建 Server = StandardServer, 然后呼叫了 Catalina#setServer()方法 getServer().setCatalina(this); getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile()); getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile()); // Stream redirection initStreams(); // Start the new server try { //初始化服務器 StandardServer#init(), 最終呼叫的是 StandardServer.initInternal() 方法 getServer().init(); } catch (LifecycleException e) { ...... } long t2 = System.nanoTime(); if(log.isInfoEnabled()) { log.info("Initialization processed in " + ((t2 - t1) / 1000000) + " ms"); } }
1. digester.parse(inputSource) 是對 conf/server.xml 進行決議, 具體決議程序比較復雜, 其中還加入了很多變數的設定和創建. 目前可以不看, 可以通過除錯來查看變數的值.
2. getServer().init() : server 是在決議server.xml時候, 創建的. 這里呼叫的是 StandardServer.init() 方法.

StandardServer本身沒有 init() 方法, init() 是父類 LifecycleBase 中的方法.
在此方法中, 呼叫了抽象方法 initInternal(). 其實就是 StandardServer#initInternal() 方法.
StandardServer#initInternal()
@Override 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 // 往 jmx 中注冊全域的 String cache,盡管這個 cache 是全域的,但是如果在同一個 jvm 中存在多個 Server, // 那么則會注冊多個不同名字的 StringCache,這種情況在內嵌的tomcat中可能會出現 onameStringCache = register(new StringCache(), "type=StringCache"); // Register the MBeanFactory JMX // 注冊MBeanFactory,用來管理Server MBeanFactory factory = new MBeanFactory(); factory.setContainer(this); onameMBeanFactory = register(factory, "type=MBeanFactory"); // Register the naming resources //往 jmx 中注冊全域的 NamingResources, NamingResourcesImpl#initInternal() 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 e) { // Ignore } catch (IOException e) { // Ignore } } } } cl = cl.getParent(); } } //一個 Server 可以有多個 Service(服務) // Initialize our defined Services for (Service service : services) { //StandardService#init(), 最侄訓呼叫 StandardService#initInternal() service.init(); } }
這里的 service 是通過 server.xml 決議得來的. service = StandardService. 同樣的, init()方法是 LifecycleBase 里的. 最終呼叫到 StandardService#initInternal().
StandardService#startInternal()
protected void initInternal() throws LifecycleException { super.initInternal(); // 1. 初始化 engine, 一個 Service 只有一個 engine if (engine != null) { //此處最侄訓呼叫 StandardEngine#initInternal() engine.init(); } // Initialize any Executors // 2. 初始化執行緒池, 默認為空, 配置 server.xml 的 tomcatThreadPool 可以改變 for (Executor executor : findExecutors()) { if (executor instanceof JmxEnabled) { ((JmxEnabled) executor).setDomain(getDomain()); } executor.init(); } // Initialize mapper listener // 3. 初始化 MapperListener, MapperListener用于注冊 Host Context Wrapper mapperListener.init(); // Initialize our defined Connectors // 4. 初始化連接器, 用來接收客戶端請求 synchronized (connectorsLock) { for (Connector connector : connectors) { try { //最終執行的是 Connector.initInternal() 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); } } } }
這里執行了4個init()方法.
1. engine也是通過決議 server.xml 來得到的. engine.init() 最終執行的是 StandardEngine#initInternal()
2. executor.init() 是初始化執行緒池的, server.xml 中, 有配置 tomcatThreadPool, 但是注釋掉了, 把它注釋回來, 然后在Connector標簽上設定 executor="tomcatThreadPool" 就可以了.
所以執行緒池默認是空
3. mapperListener.init() 是對 MapperListener 監聽器進行初始化的. 這里的init()是呼叫的父類 LifecycleBase#init() 方法. MapperListener 沒有重寫 init() 或 initInternal()
MapperListener是用來注冊 Host Context Wrapper 的.
4. connector.init() 是初始化連接器的.
StandardEngine#initInternal()
@Override 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(); super.initInternal(); }
1. getRealm 是域的一些設定, 可以不管.
2. super.initInternal() 呼叫的是父類中的方法:
//org.apache.catalina.core.ContainerBase#initInternal @Override 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(); }
這里創建了一個阻塞佇列的執行緒池, 然后繼續呼叫父類中的 initInternal 方法:
//org.apache.catalina.util.LifecycleMBeanBase#initInternal protected void initInternal() throws LifecycleException { // If oname is not null then registration has already happened via // preRegister(). if (oname == null) { mserver = Registry.getRegistry(null, null).getMBeanServer(); oname = register(this, getObjectNameKeyProperties()); } }
注意到, 這里并沒有去接著往下一層初始化了, 也就是說, Host Context Wrapper 的初始化, 不是在這里完成的.
Connector#initInternal()
protected void initInternal() throws LifecycleException { super.initInternal(); // Initialize adapter // 初始化一個配接器, 用于Coyote的Request、Response與HttpServlet的Request、Response適配的 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,這個init不是Lifecycle定義的init,而是ProtocolHandler介面的init // protocolHandler = Http11NioProtocol,其實呼叫的是 AbstractProtocol#init() protocolHandler.init(); } catch (Exception e) { throw new LifecycleException( sm.getString("coyoteConnector.protocolHandlerInitializationFailed"), e); } }
protocolHandler 是決議 server.xml 時確定的, 對應 protocol.
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
HTTP/1.1決議出來, 就是 Http11NioProtocol
如果沒有配置 protocol, 則默認使用 Http11NioProtocol
這里實際呼叫的是 org.apache.coyote.AbstractProtocol#init()
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) { rgOname = new ObjectName(domain + ":type=GlobalRequestProcessor,name=" + getName()); Registry.getRegistry(null, null).registerComponent( getHandler().getGlobal(), rgOname, null); } String endpointName = getName(); endpoint.setName(endpointName.substring(1, endpointName.length()-1)); endpoint.setDomain(domain); //NioEndpoint#init(), 呼叫的是 AbstractEndpoint#init() endpoint.init(); }
這個 NioEndpoint 是在創建 Http11NipProtocol 的時候, 創建的, 所以這里呼叫的是 NioEndpoint#init()方法.
public Http11NioProtocol() { super(new NioEndpoint()); }
NioEndpoint#init() 呼叫的是父類 org.apache.tomcat.util.net.AbstractEndpoint#init()
//org.apache.tomcat.util.net.AbstractEndpoint#init public void init() throws Exception { if (bindOnInit) { // NioEndpoint#bind() 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); } } }
bind()方法是個抽象方法, 實際呼叫的是 NipEndpoint 中的bind() 方法
//org.apache.tomcat.util.net.NioEndpoint#bind public void bind() throws Exception { if (!getUseInheritedChannel()) { // 實體化ServerSocketChannel,并且系結埠和地址 serverSock = ServerSocketChannel.open(); socketProperties.setProperties(serverSock.socket()); InetSocketAddress addr = (getAddress()!=null?new InetSocketAddress(getAddress(),getPort()):new InetSocketAddress(getPort())); // 設定最大連接數,原來是在這里設定的 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 // 初始化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)); // Initialize SSL if needed // 如果有必要的話初始化ssl initialiseSsl(); // 初始化selector selectorPool.open(); }
總結:
Bootstrap#load() 主體呼叫程序:

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/56952.html
標籤:Java
