tomcat原理解析(四):启动处理
来源:互联网 发布:淘宝百度文库财富值 编辑:程序博客网 时间:2024/05/21 09:06
一 概述
好久没有继续更新tomat相关文章了,今天刚好工作上没有什么事情做,就写写相关tomat的理解了。最近也看了别人写的tomcat理解,感觉都比自己写的好,不仅语言描述准确而且内容有深度干货也比较多。我就按照看代码的理解写写了,内容会比较肤浅。前面分析了tomcat在准备启动前做相关资源初始化处理,现在来分析下正在的启动处理代码。
二 tomcat启动处理
a.我这里仍然从Bootstrap类的main函数中daemon.start();入口开始分析,跟进到start()方法的代码如下:
public void start() throws Exception { if( catalinaDaemon==null ) init(); Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null); method.invoke(catalinaDaemon, (Object [])null); }首先判断catalinaDaemon属性是否为空,否则调用init()方法完成初始化,否则通过反射机制调用了catalinaDaemon对象的start方法。catalinaDaemon这个对象就是org.apache.catalina.startup.Catalina类的对象。
b.进入到org.apache.catalina.startup.Catalina类的start()方法查看代码。如下:
public void start() { if (getServer() == null) {//判断server对象是否为空,为空就调用load初始化 load(); } if (getServer() == null) { log.fatal("Cannot start server. Server instance is not configured."); return; } long t1 = System.nanoTime(); // Start the new server try { getServer().start(); //拿到server对象,调用start方法启动 } catch (LifecycleException e) { log.error("Catalina.start: ", e); } long t2 = System.nanoTime(); if(log.isInfoEnabled()) log.info("Server startup in " + ((t2 - t1) / 1000000) + " ms"); try { // 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); } } } catch (Throwable t) { // This will fail on JDK 1.2. Ignoring, as Tomcat can run // fine without the shutdown hook. } if (await) { await(); stop(); } }
上面代码主要涉及两部操作
- 1.判断tomcat的最外层容器server对象是否已经初始化,如果没有那么调用load进行初始化处理
- 2.getServer拿到已经初始化成功的server对象调用start()方法启动服务,这里也就是整个容器启动的入口处
c.跟进server对象的start()方法,其调用的是LifecycleBase抽象类的start()方法,查看start方法中代码最终还是调用了startInternal()方法,而且发现startInternal()方法在LifecycleBase类中是抽象的方法。按抽象模版方法模式,调用startInternal()其实调用的是子类的具体实现。我们看看LifecycleBase类中的代码
public synchronized final void start() throws LifecycleException { if (LifecycleState.STARTING_PREP.equals(state) || LifecycleState.STARTING.equals(state) || LifecycleState.STARTED.equals(state)) { if (log.isDebugEnabled()) { Exception e = new LifecycleException(); log.debug(sm.getString("lifecycleBase.alreadyStarted", toString()), e); } else if (log.isInfoEnabled()) { log.info(sm.getString("lifecycleBase.alreadyStarted", toString())); } return; } if (state.equals(LifecycleState.NEW)) { init(); } else if (!state.equals(LifecycleState.INITIALIZED) && !state.equals(LifecycleState.STOPPED)) { invalidTransition(Lifecycle.BEFORE_START_EVENT); } setState(LifecycleState.STARTING_PREP); try { startInternal(); //调用LifecycleBase类中的抽象方法startInternal方法 } catch (LifecycleException e) { setState(LifecycleState.FAILED); throw e; } if (state.equals(LifecycleState.FAILED) || state.equals(LifecycleState.MUST_STOP)) { stop(); } else { // Shouldn't be necessary but acts as a check that sub-classes are // doing what they are supposed to. if (!state.equals(LifecycleState.STARTING)) { invalidTransition(Lifecycle.AFTER_START_EVENT); } setState(LifecycleState.STARTED); } }下面就是LifecycleBase类中的抽象方法。
protected abstract void startInternal() throws LifecycleException;
d.前面我们介绍过server的表中实现是StandardServer类,查看该类的startInternal具体实现。代码如下:
protected void startInternal() throws LifecycleException { fireLifecycleEvent(CONFIGURE_START_EVENT, null); setState(LifecycleState.STARTING); // Start our defined Services synchronized (services) { for (int i = 0; i < services.length; i++) { services[i].start();//循环调用service接口实现类的start方法来启动容器 } } }
StandardServer类中的startInternal做了一件事情,就是通过遍历Service数组循环启动service对象,调用start()方法。前面架构图中介绍过service接口的标准实现是StandardService类,所以start方法按照前面介绍的语意,仍然还是调用StandardService类中的startInternal方法。
e.查看StandardService的startInternal方法启动代码。如下:
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 (container != null) { synchronized (container) { container.start(); //StandardEngine启动 } } synchronized (executors) { for ( int i=0; i<executors.size(); i++ ) { executors.get(i).start(); //线程池启动 } } // Start our defined Connectors second synchronized (connectors) { for (int i = 0; i < connectors.length; i++) { ((Lifecycle) connectors[i]).start(); //连接器启动 } } }
StandardService类中的startInternal方法做了3件事情
- 1.启动StandardEngine容器
- 2.循环启动线程池。没看太懂这里的线程池是做什么用的?后面有时间再研究下!
- 3.循环启动Connector数组。
f.这里我就直接跟踪tomcat启动的主流程了,其它细节的地方就不仔细看啦!立即进入到Connector类的startInternal方法
protected void startInternal() throws LifecycleException { setState(LifecycleState.STARTING); // Protocol handlers do not follow Lifecycle conventions. // protocolHandler.init() needs to wait until the connector.start() try { protocolHandler.init(); //初始化协议处理,protocolHandler时一个接口,具体实现看具体实现 } catch (Exception e) { throw new LifecycleException (sm.getString ("coyoteConnector.protocolHandlerInitializationFailed", e)); } 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)); } // MapperListener doesn't follow Lifecycle conventions either mapperListener.init(); }g.初始化协议处理,protocolHandler属性是一个ProtocolHandler类型的,ProtocolHandler接口类的具体实现是用的什么类,我们查看Connector类的带参构造函数。代码如下:
public Connector(String protocol) { setProtocol(protocol); // Instantiate protocol handler try { Class<?> clazz = Class.forName(protocolHandlerClassName); this.protocolHandler = (ProtocolHandler) clazz.newInstance(); } catch (Exception e) { log.error (sm.getString ("coyoteConnector.protocolHandlerInstantiationFailed", e)); } }可以看出Connector类在实例化的时候传入了一个字符串protocol参数。在前面章节《tomcat原理解析(三):资源初始化》介绍Connector初始化的时候,通过Connector con = new Connector(attributes.getValue("protocol"));来实例化。这里attributes.getValue("protocol")取的值实际就是在解析server.xml时的
<Connector port="80" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> protocol节点的值。通过server.xml配置文件看出在初始化Connector连接器的时候已经默认指定了协议处理器对象。到这里继续跟进setProtocol(protocol);中代码。如下:
public void setProtocol(String protocol) { 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.Http11Protocol"); } else if ("AJP/1.3".equals(protocol)) { setProtocolHandlerClassName ("org.apache.coyote.ajp.AjpProtocol"); } else if (protocol != null) { setProtocolHandlerClassName(protocol); } } }以上的方法跟进传入的protocol字符串来区分使用什么类型的协议处理器类。在确定使用什么协议处理后,通过Class.forName来实例化协议处理器对象。在这里tomcat默认使用的org.apache.coyote.http11.Http11Protocol协议处理。
我们看下Http11Protocol类中init做了什么事情,代码如下:
@Override public void init() throws Exception { ((JIoEndpoint)endpoint).setName(getName());//设置名称 ((JIoEndpoint)endpoint).setHandler(cHandler);//设置连接对象处理器,在拿到socket对象后会传入处理器中 // Verify the validity of the configured socket factory try {//根据条件初始化socketFacor if (isSSLEnabled()) { sslImplementation = SSLImplementation.getInstance(sslImplementationName); socketFactory = sslImplementation.getServerSocketFactory(); ((JIoEndpoint)endpoint).setServerSocketFactory(socketFactory); } else if (socketFactoryName != null) { socketFactory = (ServerSocketFactory) Class.forName(socketFactoryName).newInstance(); ((JIoEndpoint)endpoint).setServerSocketFactory(socketFactory); } } catch (Exception ex) { log.error(sm.getString("http11protocol.socketfactory.initerror"), ex); throw ex; } if (socketFactory!=null) { Iterator<String> attE = attributes.keySet().iterator(); while( attE.hasNext() ) { String key = attE.next(); Object v=attributes.get(key); socketFactory.setAttribute(key, v); } } try { endpoint.init();//JioEndpoint对象初始化处理 } catch (Exception ex) { log.error(sm.getString("http11protocol.endpoint.initerror"), ex); throw ex; } if (log.isInfoEnabled()) log.info(sm.getString("http11protocol.init", getName())); }
上面的初始化处理主要做了3件事情1.设置JIoEndpoint的名称2.设置Http11ConnectionHandler类连接对象处理3.调用JIoEndpoint类的init方法进行初始化。我们看看JIoEndpoint类中的inti方法中的代码,代码如下:
public void init() throws Exception { if (initialized) return; // Initialize thread count defaults for acceptor if (acceptorThreadCount == 0) { acceptorThreadCount = 1;//设置连接器中接收socket请求的线程数量 } if (serverSocketFactory == null) { serverSocketFactory = ServerSocketFactory.getDefault();//得到默认创建socket的对象,默认使用的DefaultServerSocketFactory类 } if (isSSLEnabled()) { //设置了一系列的属性,貌似跟socket的参数有关系,具体还不是非常清楚 serverSocketFactory.setAttribute(SSL_ATTR_ALGORITHM, getAlgorithm()); serverSocketFactory.setAttribute(SSL_ATTR_CLIENT_AUTH, getClientAuth()); serverSocketFactory.setAttribute(SSL_ATTR_KEYSTORE_FILE, getKeystoreFile()); serverSocketFactory.setAttribute(SSL_ATTR_KEYSTORE_PASS, getKeystorePass()); serverSocketFactory.setAttribute(SSL_ATTR_KEYSTORE_TYPE, getKeystoreType()); serverSocketFactory.setAttribute(SSL_ATTR_KEYSTORE_PROVIDER, getKeystoreProvider()); serverSocketFactory.setAttribute(SSL_ATTR_SSL_PROTOCOL, getSslProtocol()); serverSocketFactory.setAttribute(SSL_ATTR_CIPHERS, getCiphers()); serverSocketFactory.setAttribute(SSL_ATTR_KEY_ALIAS, getKeyAlias()); serverSocketFactory.setAttribute(SSL_ATTR_KEY_PASS, getKeyPass()); serverSocketFactory.setAttribute(SSL_ATTR_TRUSTSTORE_FILE, getTruststoreFile()); serverSocketFactory.setAttribute(SSL_ATTR_TRUSTSTORE_PASS, getTruststorePass()); serverSocketFactory.setAttribute(SSL_ATTR_TRUSTSTORE_TYPE, getTruststoreType()); serverSocketFactory.setAttribute(SSL_ATTR_TRUSTSTORE_PROVIDER, getTruststoreProvider()); serverSocketFactory.setAttribute(SSL_ATTR_TRUSTSTORE_ALGORITHM, getTruststoreAlgorithm()); serverSocketFactory.setAttribute(SSL_ATTR_CRL_FILE, getCrlFile()); serverSocketFactory.setAttribute(SSL_ATTR_TRUST_MAX_CERT_LENGTH, getTrustMaxCertLength()); serverSocketFactory.setAttribute(SSL_ATTR_SESSION_CACHE_SIZE, getSessionCacheSize()); serverSocketFactory.setAttribute(SSL_ATTR_SESSION_TIMEOUT, getSessionTimeout()); serverSocketFactory.setAttribute(SSL_ATTR_ALLOW_UNSAFE_RENEG, getAllowUnsafeLegacyRenegotiation()); } if (serverSocket == null) { //serverSocket对象为空时即刻创建 try { if (getAddress() == null) { serverSocket = serverSocketFactory.createSocket(getPort(), getBacklog());//根据端口号创建serverSocket对象 } else { serverSocket = serverSocketFactory.createSocket(getPort(), getBacklog(), getAddress()); } } catch (BindException orig) { String msg; if (getAddress() == null) msg = orig.getMessage() + " <null>:" + getPort(); else msg = orig.getMessage() + " " + getAddress().toString() + ":" + getPort(); BindException be = new BindException(msg); be.initCause(orig); throw be; } } //if( serverTimeout >= 0 ) // serverSocket.setSoTimeout( serverTimeout ); initialized = true; }
到这里Http11Protocol 协议处理器初始化已经完成,intit方面主要做了3件事情如下
- 1连接器中接收socket连接的线程数量,
- 2初始化ServerSocketFactory serverSocketFactory对象,该对象默认使用的DefaultServerSocketFactory类
- 3根据端口号初始化ServerSocket对象
h.我们接着看Connector类的startInternal方法中的protocolHandler.start()的代码。代码如下
public void start() throws Exception { if (this.domain != null) { try { tpOname = new ObjectName(domain + ":" + "type=ThreadPool,name=" + getName()); Registry.getRegistry(null, null).registerComponent(endpoint, tpOname, null ); } catch (Exception e) { log.error("Can't register endpoint"); } rgOname=new ObjectName(domain + ":type=GlobalRequestProcessor,name=" + getName()); Registry.getRegistry(null, null).registerComponent( cHandler.global, rgOname, null ); } try { endpoint.start(); } catch (Exception ex) { log.error(sm.getString("http11protocol.endpoint.starterror"), ex); throw ex; } if (log.isInfoEnabled()) log.info(sm.getString("http11protocol.start", getName())); }主要就是调用了JIoEndpoint类的start()方法。继续跟进到JIoEndpoint类中的start方法代码。如下:
@Override public void start() throws Exception { // Initialize socket if not done before if (!initialized) { init(); } if (!running) { running = true; paused = false; // Create worker collection if (getExecutor() == null) { createExecutor(); } // Start acceptor threads for (int i = 0; i < acceptorThreadCount; i++) { Thread acceptorThread = new Thread(new Acceptor(), getName() + "-Acceptor-" + i); acceptorThread.setPriority(threadPriority); acceptorThread.setDaemon(getDaemon()); acceptorThread.start(); } } }
主要完成两件事情
- 调用JIoEndpoint类的父类AbstractEndpoint的createExecutor方法创建了一个线程池
- 循环创建接受socket请求线程,前面我们看到JIoEndpoint在init方法中初始化是设置的为一个。所以这里只创建了一个线程。新建线程里面的
Acceptor类实现了线程Runnable接口。Acceptor类也是JIoEndpoint类中的内部类。
解析分析Acceptor线程类的流程,看到这里似乎明白了tomcat客户端请求处理也是通过socket来实现的,是不是跟前面章节中的《tomcat原理解析(一):一个简单的实现》有点像。 代码如下:
protected class Acceptor implements Runnable { /** * The background thread that listens for incoming TCP/IP connections and * hands them off to an appropriate processor. */ public void run() { // Loop until we receive a shutdown command while (running) { // Loop if endpoint is paused while (paused) { try { Thread.sleep(1000); } catch (InterruptedException e) { // Ignore } } // Accept the next incoming connection from the server socket try { Socket socket = serverSocketFactory.acceptSocket(serverSocket);//通过serverSocketFacory来接收客户端socket请求,并拿到socket对象 serverSocketFactory.initSocket(socket);//socket初始化,奇怪里面怎么是空实现 // Hand this socket off to an appropriate processor if (!processSocket(socket)) {//传入socket对象到SocketProcessor类中进行业务处理 // Close socket right away try { socket.close(); } catch (IOException e) { // Ignore } } }catch ( IOException x ) { if ( running ) log.error(sm.getString("endpoint.accept.fail"), x); } catch (Throwable t) { log.error(sm.getString("endpoint.accept.fail"), t); } // The processor will recycle itself when it finishes } } }到这里整个容器已经启动完成,并开启了ServerSocket监听前端socket的请求
三 总结
在整个章节中都在描述tomcat的启动流程,其实最终目的就是要启动socket的监听,然后等待链接。对socket链接处理核心的过程都在JIoEndpoint类中,tomcat启动的过程跟初始化的处理非常相似,都是在父类LifecycleBase(具体类之前的关系图可以查看前面的《tomcat原理解析(二):整体架构》)中定义抽象的startInternal,然后由子类来具体实现,这就是使用抽象模版方法模式。所以学习和掌握设计模式能够有助于更好的理解源码。下面是我整理的一个序列图,展现了启动时的调用关系。下面章节开始分析浏览器客户端请求tomcat服务器如何找到想要的资源。
0 0
- tomcat原理解析(四):启动处理
- tomcat原理解析(五):http请求处理
- Tomcat源码解析(四):tomcat核心组件初始化和启动
- tomcat 解析(四)-处理http请求过程
- tomcat启动解析
- tomcat服务启动解析
- Tomcat启动流程解析
- tomcat流程原理解析
- Tomcat运行原理解析
- Tomcat工作原理(四)-tomcat默认连接器
- Tomcat原理:启动过程分析
- Tomcat启动过程原理详解
- Tomcat启动过程原理详解
- Tomcat启动过程原理详解
- Tomcat原理:启动过程分析
- Tomcat启动过程原理详解
- Tomcat启动过程原理详解
- Tomcat启动过程原理详解
- eclipse运行程序崩溃,我的坑啊
- JavaScript 基本语法(运算符,语句,函数)
- 淘宝JAVA中间件Diamond详解(二)---原理介绍
- Caffe源码解析3:Layer
- AlertDialog 自由关闭
- tomcat原理解析(四):启动处理
- weka API连接数据库
- ListenableFuture in Guava
- google工具的Coverage代码覆盖率详解
- PHP文件上传至另一台服务器
- Java 编程下字符串的 16 位、32位 MD5 加密
- TCP 三次握手与四次挥手 看了你必懂
- IntelliJ IDEA使用教程三 SVN的集成与使用
- 影响mysql性能的五个方面