一、Connector内部分析
Connector的内部结构
Connector的作用:底层使用Socket连接,接收请求并把请求封装成Request和Response。
(Connector实现了Http协议和TCP/IP协议,Request和Response内部是由Http协议封装)
(Connector在Catalina调用load方法创建,生命周期方法在Service中调用。)
封装完后------》交给Container处理------》返回给Connector------》Connector使用Socket将结果返回给客户端。
ProtocolHandler 包含三个组件-------》1、Endpoint(AbstractEndpoint) 处理底层Socket的网络连接 ----用来实现TCP/IP协议
Acceptor 用于监听请求,AsyncTimeout用于检查异步request的超时,Handler用于处理接收到的Socket.
-------》2、Processor 将Endpoint接收到的Endpoint封装成Request ----实现HTTP协议
-------》3、Adapter 将Request封装成交给Container处理。 ----请求转到Servlet容器处理
Connector的构造方法:
org.apache.catalina.connector.connector类
public Connector() {
this(null);
}
public Connector(String protocol) {
setProtocol(protocol);
// Instantiate protocol handler
ProtocolHandler p = null;
try {
Class<?> clazz = Class.forName(protocolHandlerClassName);
//创建ProtocolHandler对象实例
p = (ProtocolHandler) clazz.getDeclaredConstructor().newInstance();
} catch (Exception e) {
log.error(sm.getString(
"coyoteConnector.protocolHandlerInstantiationFailed"), e);
} finally {
this.protocolHandler = p;
}
if (!Globals.STRICT_SERVLET_COMPLIANCE) {
URIEncoding = "UTF-8";
URIEncodingLower = URIEncoding.toLowerCase(Locale.ENGLISH);
}
}
//// setProtocol(protocol);方法
/**
* Set the Coyote protocol which will be used by the connector.
*
* @param protocol The Coyote protocol name
*/
public void setProtocol(String protocol) {
//根据协议类型 设置protocolHandlerClassName
if (AprLifecycleListener.isAprAvailable()) {
if ("HTTP/1.1".equals(protocol)) {
setProtocolHandlerClassName
("org.apache.coyote.http11.Http11AprProtocol");
} else if ("AJP/1.3".equals(protocol)) {
setProtocolHandlerClassName
("org.apache.coyote.ajp.AjpAprProtocol");
} else if (protocol != null) {
setProtocolHandlerClassName(protocol);
} else {
setProtocolHandlerClassName
("org.apache.coyote.http11.Http11AprProtocol");
}
} else {
if ("HTTP/1.1".equals(protocol)) {
setProtocolHandlerClassName
("org.apache.coyote.http11.Http11NioProtocol");
} else if ("AJP/1.3".equals(protocol)) {
setProtocolHandlerClassName
("org.apache.coyote.ajp.AjpNioProtocol");
} else if (protocol != null) {
setProtocolHandlerClassName(protocol);
}
}
}
/**
* Coyote Protocol handler class name.
* Defaults to the Coyote HTTP/1.1 protocolHandler.
*/
protected String protocolHandlerClassName =
"org.apache.coyote.http11.Http11NioProtocol";
/**
* Set the class name of the Coyote protocol handler which will be used
* by the connector.
*
* @param protocolHandlerClassName The new class name
*/
public void setProtocolHandlerClassName(String protocolHandlerClassName) {
this.protocolHandlerClassName = protocolHandlerClassName;
}
Connector(通过构造方法)创建对象实例的时候同时创建了ProtocolHandler对象实例。
用 setProtocol(protocol); 设置好的protocolHandlerClassName的类(默认是org.apache.coyote.http11.Http11NioProtocol)
然后用 Class<?> clazz = Class.forName(protocolHandlerClassName);创建ProtocolHandler对象
上面代码中的 Apr是 Apache Portable Runtime的缩写 -->Apache可移植运行库
主要为上层的应用程序提供一个可以跨越多操作系统平台使用的底层支持接口库。在早期 的Apache版本中,应用程序本身必须能够处理各种具体操作系统平台的细节,并针对不同的平台调用不同的处理函数。
目前APR主要还是由Apache使用,不过由于APR的较好的移植性,因此一些需要进行移植的C程序也开始使用APR
如果使用Apr需要先安装,安装后Tomcat可以检测的出来。
AprLifecycleListener.isAprAvailable() 判断Apr是否可用。
1.1 Connector的生命周期方法:
org.apache.catalina.connector.connector类:
@Override
protected void initInternal() throws LifecycleException {
super.initInternal();
// Initialize adapter
adapter = new CoyoteAdapter(this);
protocolHandler.setAdapter(adapter);
// Make sure parseBodyMethodsSet has a default
if( null == parseBodyMethodsSet ) {
setParseBodyMethods(getParseBodyMethods());
}
if (protocolHandler.isAprRequired() &&
!AprLifecycleListener.isAprAvailable()) {
throw new LifecycleException(
sm.getString("coyoteConnector.protocolHandlerNoApr",
getProtocolHandlerClassName()));
}
try {
protocolHandler.init();
} catch (Exception e) {
throw new LifecycleException
(sm.getString
("coyoteConnector.protocolHandlerInitializationFailed"), e);
}
}
/**
* Begin processing requests via this Connector.
*
* @exception LifecycleException if a fatal startup error occurs
*/
@Override
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) {
String errPrefix = "";
if(this.service != null) {
errPrefix += "service.getName(): \"" + this.service.getName() + "\"; ";
}
throw new LifecycleException
(errPrefix + " " + sm.getString
("coyoteConnector.protocolHandlerStartFailed"), e);
}
}
@Override
protected void destroyInternal() throws LifecycleException {
try {
protocolHandler.destroy();
} catch (Exception e) {
throw new LifecycleException
(sm.getString
("coyoteConnector.protocolHandlerDestroyFailed"), e);
}
if (getService() != null) {
getService().removeConnector(this); //service移除Connector
}
super.destroyInternal();
}
1.2 ProtocolHandler类:
ProtocolHandler下面有三种协议类型:AJP,Http,Spdy。
AJP协议-----》(英文全称Apache JServ Protocol),Apache的定向包协议,是长连接,用于客服端(前端服务器)建立 连接 通信。
Spdy协议------》应用不广泛,SPDY(读作“SPeeDY”)是Google开发的基于TCP的应用 层协议,用以最小化网络延迟,提升网络速度,优化用户的网络使用体验。SPDY并不是一种用于 替代HTTP的协议,而是对HTTP协议的增强.
Http11NioProtocol的四个周期方法都在父类AbstractProtocol类实现--》 代码如下:
org.apache.coyote.AbstractProtocol类:
/*
* NOTE: There is no maintenance of state or checking for valid transitions
* within this class. It is expected that the connector will maintain state
* and prevent invalid state transitions.
*/
@Override
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) {
try {
tpOname = new ObjectName(domain + ":" +
"type=ThreadPool,name=" + getName());
Registry.getRegistry(null, null).registerComponent(endpoint,
tpOname, null);
} catch (Exception e) {
getLog().error(sm.getString(
"abstractProtocolHandler.mbeanRegistrationFailed",
tpOname, getName()), e);
}
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));
try {
endpoint.init();
} catch (Exception ex) {
getLog().error(sm.getString("abstractProtocolHandler.initError",
getName()), ex);
throw ex;
}
}
@Override
public void start() throws Exception {
if (getLog().isInfoEnabled())
getLog().info(sm.getString("abstractProtocolHandler.start",
getName()));
try {
endpoint.start();
} catch (Exception ex) {
getLog().error(sm.getString("abstractProtocolHandler.startError",
getName()), ex);
throw ex;
}
}
protocolHandlerClassName默认配置 --》org.apache.coyote.http11.Http11NioProtocol类:
/**
* Abstract the protocol implementation, including threading, etc.
* Processor is single threaded and specific to stream-based protocols,
* will not fit Jk protocols like JNI.
*
* @author Remy Maucherat
* @author Costin Manolache
*/
public class Http11NioProtocol extends AbstractHttp11JsseProtocol<NioChannel> {
private static final Log log = LogFactory.getLog(Http11NioProtocol.class);
@Override
protected Log getLog() { return log; }
@Override
protected AbstractEndpoint.Handler getHandler() {
return cHandler;
}
/**// Constants类的
* // public static final int DEFAULT_CONNECTION_LINGER = -1;
* // public static final int DEFAULT_CONNECTION_TIMEOUT = 60000;
* // public static final boolean DEFAULT_TCP_NO_DELAY = true;
**/
public Http11NioProtocol() {
endpoint=new NioEndpoint(); //创建Endpoint
cHandler = new Http11ConnectionHandler(this); //创建Http11ConnectionHandler
((NioEndpoint) endpoint).setHandler(cHandler);
//父类AbstractProtocol的endpoint.setSoLinger(soLinger);
setSoLinger(Constants.DEFAULT_CONNECTION_LINGER);
//父类AbstractProtocol的endpoint.setSoTimeout(timeout);
setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT);
//父类AbstractProtocol的endpoint.setTcpNoDelay(tcpNoDelay);
setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY);
}
public NioEndpoint getEndpoint() {
return ((NioEndpoint)endpoint);
}
。。。省略部分代码
}
1.3 AbstractEndpoint类(endpoint):
AbstractEndpoint类 分析:
org.apache.tomcat.util.net.AbstractEndpoint
//1、init方法
public final void init() throws Exception {
testServerCipherSuitesOrderSupport();
if (bindOnInit) {
bind();
bindState = BindState.BOUND_ON_INIT;
}
}
protected void testServerCipherSuitesOrderSupport() {
// Only test this feature if the user explicitly requested its use.
if(!"".equals(getUseServerCipherSuitesOrder().trim()) && !JreCompat.isJre8Available()) {
throw new UnsupportedOperationException(
sm.getString("endpoint.jsse.cannotHonorServerCipherOrder"));
}
}
//2、start方法
public final void start() throws Exception {
if (bindState == BindState.UNBOUND) {
bind();
bindState = BindState.BOUND_ON_START;
}
startInternal();
}
//bind()具体实现方法在子类里 如:--》org.apache.tomcat.util.net.NioEndpoint
/**
* Initialize the endpoint.
*/
@Override
public void bind() throws Exception {
serverSock = ServerSocketChannel.open();
socketProperties.setProperties(serverSock.socket());
InetSocketAddress addr = (getAddress()!=null?new InetSocketAddress(getAddress(),getPort()):new InetSocketAddress(getPort()));
serverSock.socket().bind(addr,getBacklog());
serverSock.configureBlocking(true); //mimic APR behavior
serverSock.socket().setSoTimeout(getSocketProperties().getSoTimeout());
// 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;
}
stopLatch = new CountDownLatch(pollerThreadCount);
// Initialize SSL if needed
if (isSSLEnabled()) {
SSLUtil sslUtil = handler.getSslImplementation().getSSLUtil(this);
sslContext = sslUtil.createSSLContext();
sslContext.init(wrap(sslUtil.getKeyManagers()),
sslUtil.getTrustManagers(), null);
SSLSessionContext sessionContext =
sslContext.getServerSessionContext();
if (sessionContext != null) {
sslUtil.configureSessionContext(sessionContext);
}
// Determine which cipher suites and protocols to enable
enabledCiphers = sslUtil.getEnableableCiphers(sslContext);
enabledProtocols = sslUtil.getEnableableProtocols(sslContext);
}
if (oomParachute>0) reclaimParachute(true);
selectorPool.open();
}
//startInternal()具体实现方法在子类里--》org.apache.tomcat.util.net.NioEndpoint
/**
* Start the NIO endpoint, creating acceptor, poller threads.
*/
@Override
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 //创建Executor
if ( getExecutor() == null ) {
createExecutor();
}
initializeConnectionLatch();
// Start poller threads //启动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();
}
startAcceptorThreads(); //启动Acceptor线程
}
}
org.apache.tomcat.util.net.AbstractEndpoint类:
protected final void startAcceptorThreads() {
int count = getAcceptorThreadCount();
acceptors = new Acceptor[count];
f