Tomcat Connector组件的初始化
文章目录
前言
Connector组件是Tomcat两大核心组件之一,其主要负责监听服务器指定端口的请求,解析请求报文为Request对象与Response对象。后将Request与Response传递至Container组件进行后续处理。
一、Connector组件整体结构
Connector运行基本流程如下所示。Endpoint负责监听请求,并将Socket传递至Processor。Processor对Socket中的请求报文进行解析,封装出Tomcat Request与Tomcat Response对象。Adaptor将获取到到的Tomcat Request与Tomcat Response对象进行进一步的解析,获得Servlet Request与Servlet Response,后继续向Container组件传递。
二、Connector组件的初始化
1.构造方法
在Connector类的构造方法中使用反射构造出Protocol实例(默认使用org.apache.coyote.http11.Http11NioProtocol类)。经类型转换后将ProtocolHandle对象的引用赋值给Connector对象的protocolHandle属性。
public Connector(String protocol) {
setProtocol(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;
}
if (Globals.STRICT_SERVLET_COMPLIANCE) {
uriCharset = StandardCharsets.ISO_8859_1;
} else {
uriCharset = StandardCharsets.UTF_8;
}
// Default for Connector depends on this (deprecated) system property
if (Boolean.parseBoolean(System.getProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "false"))) {
encodedSolidusHandling = EncodedSolidusHandling.DECODE;
}
}
在Http11NioProtocol的构造函数中调用了父类的构造函数,为Http11NioProtocol的endPoint属性赋值。我们可以一直追溯下去,直到AbstractHttp11Protocol类,我们可以看到AbstractHttp11Protocol的构造函数在调用了父类的构造函数后还为EndPoint类创建了Handle实例的引用。
public Http11NioProtocol() {
super(new NioEndpoint());
}
public AbstractHttp11Protocol(AbstractEndpoint<S> endpoint) {
super(endpoint);
setConnectionTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT);
//创建Handle实例
ConnectionHandler<S> cHandler = new ConnectionHandler<>(this);
setHandler(cHandler);
//为endpoint设置handle引用
getEndpoint().setHandler(cHandler);
}
2.初始化触发
Connector组件的初始化操作,由StandardService的initInternal()调用connector.init()触发:
@Override
protected void initInternal() throws LifecycleException {
super.initInternal();
if (engine != null) {
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进行初始化操作
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);
}
}
}
}
3.Connector的initInternal方法
由于Connector类继承了LifecycleBase抽象类,故connector.init()其实是调用了从LifecycleBase继承来的init()方法。
在init()方法内部,LifecycleBase又通过调用各个实现类 各自实现的initInternal()方法,来完成各个组件的定制化的初始化过程。
public final synchronized void init() throws LifecycleException {
if (!state.equals(LifecycleState.NEW)) {
invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
}
try {
setStateInternal(LifecycleState.INITIALIZING, null, false);
//在connector初始化过程中,这里会调用Connector的initInternal()方法
initInternal();
setStateInternal(LifecycleState.INITIALIZED, null, false);
} catch (Throwable t) {
handleSubClassException(t, "lifecycleBase.initFail", toString());
}
}
protected void initInternal() throws LifecycleException {
super.initInternal();
// 初始化Adapter组件
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 {
//初始化protocolHandle组件
protocolHandler.init();
} catch (Exception e) {
throw new LifecycleException(
sm.getString("coyoteConnector.protocolHandlerInitializationFailed"), e);
}
}
4.protocolHandler.init()
protocolHandler.init()主要调用了AbstractProtocol抽象类的init()方法,其主要是用于触发endpoint的初始化方法
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的初始化方法
endpoint.init();
}
5.endpoint.bind()
endpoint.init()由NioEndpoint从AbstractEndpoint抽象类继承而来,该方法内部主要调用了AbstractEndpoint中的抽象方法bind(),bind()方法的具体实现由具体的实现类进行复写。
在此处默认由NioEndpoint类实现对bind()方法的复写。
public void bind() throws Exception {
if (!getUseInheritedChannel()) {
//绑定要监听的端口地址 如:0.0.0.0/0.0.0.0:8080
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
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
initialiseSsl();
selectorPool.open();
}
参考文献
链接: tomcat之Connector的结构.
链接: Tomcat8源码分析系列-启动分析(二) Catalina初始化.