前言
在前幾篇文章(五、六、七、八、九)中,介紹了 Tomcat 中 Container 及其相關組件,包括 Engine、Host、Context、Wrapper、Pipeline 和 Valve。在這篇文章中分析到了 Service 的 initInternal 和 startInternal 方法,在其中就調用了 Connector 的 init 和 start 方法。Connector 繼承自 LifecycleMBeanBase。apache
1. Connector 構造方法segmentfault
/** * Defaults to using HTTP/1.1 NIO implementation. */ public Connector() { this("org.apache.coyote.http11.Http11NioProtocol"); } public Connector(String protocol) { boolean aprConnector = AprLifecycleListener.isAprAvailable() && AprLifecycleListener.getUseAprConnector(); if ("HTTP/1.1".equals(protocol) || protocol == null) { if (aprConnector) { protocolHandlerClassName = "org.apache.coyote.http11.Http11AprProtocol"; } else { protocolHandlerClassName = "org.apache.coyote.http11.Http11NioProtocol"; } } else if ("AJP/1.3".equals(protocol)) { if (aprConnector) { protocolHandlerClassName = "org.apache.coyote.ajp.AjpAprProtocol"; } else { protocolHandlerClassName = "org.apache.coyote.ajp.AjpNioProtocol"; } } else { protocolHandlerClassName = protocol; } // Instantiate protocol handler ProtocolHandler p = null; try { Class<?> clazz = Class.forName(protocolHandlerClassName); p = (ProtocolHandler) clazz.getConstructor().newInstance(); } catch (Exception e) { log.error(sm.getString( "coyoteConnector.protocolHandlerInstantiationFailed"), e); } finally { this.protocolHandler = p; } // Default for Connector depends on this system property setThrowOnFailure(Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")); }
在構造方法中,根據配置建立了一個 ProtocolHandler 對象,並把它賦值得 protocolHandler 屬性。能夠看出,ProtocolHandler 的默認實現類是 Http11NioProtocol。
2. Connector#initInternal 方法app
@Override protected void initInternal() throws LifecycleException { super.initInternal(); if (protocolHandler == null) { throw new LifecycleException( sm.getString("coyoteConnector.protocolHandlerInstantiationFailed")); } // Initialize adapter adapter = new CoyoteAdapter(this); protocolHandler.setAdapter(adapter); if (service != null) { protocolHandler.setUtilityExecutor(service.getServer().getUtilityExecutor()); } // 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(); } catch (Exception e) { throw new LifecycleException( sm.getString("coyoteConnector.protocolHandlerInitializationFailed"), e); } }
在 initInternal 裏,首先建立了一個 CoyoteAdapter 對象,並調用 protocolHandler.setAdapter(adapter),把這個 CoyoteAdapter 對象賦值給 protocolHandler 的 Adapter 類型的 adapter 屬性(在 protocolHandler 的實現類的父類 AbstractProtocol 裏)。這個 Adapter 對象是 ProtocolHandler 用來處理請求的。
而後對 ProtocolHandler 的屬性作了一些設值。
最後調用了 ProtocolHandler#init 方法。
ProtocolHandler 是 Connector 用來處理鏈接和請求的很是關鍵的組件。後面會單獨分析。
3. Connector#startInternal 方法ide
@Override protected void startInternal() throws LifecycleException { // Validate settings before starting if (getPortWithOffset() < 0) { throw new LifecycleException(sm.getString( "coyoteConnector.invalidPort", Integer.valueOf(getPortWithOffset()))); } setState(LifecycleState.STARTING); try { protocolHandler.start(); } catch (Exception e) { throw new LifecycleException( sm.getString("coyoteConnector.protocolHandlerStartFailed"), e); } }
Connector#startInternal 裏最主要的就是調用 ProtocolHandler#init 方法。ui
小結
本文分析了 Connector 的初始化和啓動過程,能夠看出,最重要的步驟就是初始化並啓動了 ProtocolHandler。this