`
yayagepei
  • 浏览: 7143 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

tomcat源码分析系列之启动---庐山真面目

阅读更多

     上回我们说到Http11Protocol,它的init 和start方法:

/*
     * 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;
        }
    }

 2个逻辑主要都调用了endpoint的对应方法,endpoint是JIoEndpoint的实例,JIoEndpoint实现了一个简单的服务器模型:监听线程接收到一个socket连接就会启动一个工作线程来处理。这里面有我们期待已久的Socket出现了。JIoEndpoint实现了虚类AbstractEndpoint,上面提到的endpoint.init()和endpoint.start()都是AbstractEndpoint里的方法

 public final void init() throws Exception {
        if (bindOnInit) {
            bind();
            bindState = BindState.BOUND_ON_INIT;
        }
    }
    
    public final void start() throws Exception {
        if (bindState == BindState.UNBOUND) {
            bind();
            bindState = BindState.BOUND_ON_START;
        }
        startInternal();
    }

 我们看JIoEndpoint的bind方法:

public void bind() throws Exception {

        // Initialize thread count defaults for acceptor
        if (acceptorThreadCount == 0) {
            acceptorThreadCount = 1;
        }
        // Initialize maxConnections
        if (getMaxConnections() == 0) {
            // User hasn't set a value - use the default
            setMaxConnections(getMaxThreads());
        }

        if (serverSocketFactory == null) {
            if (isSSLEnabled()) {
                serverSocketFactory =
                    handler.getSslImplementation().getServerSocketFactory(this);
            } else {
                serverSocketFactory = new DefaultServerSocketFactory(this);
            }
        }

        if (serverSocket == null) {
            try {
                if (getAddress() == null) {
                    serverSocket = serverSocketFactory.createSocket(getPort(),
                            getBacklog());
                } 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;
            }
        }
        
    }
    

 bind方法主要实例化了serverSocket,接着看startInternal方法

@Override
    public void startInternal() throws Exception {

        if (!running) {
            running = true;
            paused = false;

            // Create worker collection
            if (getExecutor() == null) {
                createExecutor();
            }
            
            initializeConnectionLatch();

            // 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();
            }
            
            // Start async timeout thread
            Thread timeoutThread = new Thread(new AsyncTimeout(),
                    getName() + "-AsyncTimeout");
            timeoutThread.setPriority(threadPriority);
            timeoutThread.setDaemon(true);
            timeoutThread.start();
        }
    }
startInternal 首先创建了一个处理队列,
然后生成一个最大连接数限制对象LimitLatch,
生成一组接收线程,并启动所有线程。
生成一个后台线程用以检查超时请求。 
我们看Acceptor的run方法:
public void run() {

            int errorDelay = 0;

            // Loop until we receive a shutdown command
            while (running) {

                // Loop if endpoint is paused
                while (paused && running) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // Ignore
                    }
                }

                if (!running) {
                    break;
                }
                try {
                    //if we have reached max connections, wait
                    countUpOrAwaitConnection();
                    
                    Socket socket = null;
                    try {
                        // Accept the next incoming connection from the server
                        // socket
                        socket = serverSocketFactory.acceptSocket(serverSocket);
                    } catch (IOException ioe) {
                        // Introduce delay if necessary
                        errorDelay = handleExceptionWithDelay(errorDelay);
                        // re-throw
                        throw ioe;
                    }
                    // Successful accept, reset the error delay
                    errorDelay = 0;

                    // Configure the socket
                    if (setSocketOptions(socket)) {
                        // Hand this socket off to an appropriate processor
                        if (!processSocket(socket)) {
                            // Close socket right away
                            try {
                                socket.close();
                            } catch (IOException e) {
                                // Ignore
                            }
                        }
                    } else {
                        // 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 (NullPointerException npe) {
                    if (running) {
                        log.error(sm.getString("endpoint.accept.fail"), npe);
                    }
                } catch (Throwable t) {
                    ExceptionUtils.handleThrowable(t);
                    log.error(sm.getString("endpoint.accept.fail"), t);
                }
                // The processor will recycle itself when it finishes
            }
        }
    } 
这是一个典型的socket监听处理程序。目前我们不去追究里面太多的细节,先形成一个整体的形象上的认识,到目前
为止,监听真正的建立起来了,意味着tomcat可以接受、处理请求了。
分享到:
评论

相关推荐

    apache-tomcat-9.0.45-windows-x64

    apache-tomcat-9.0.45-windows-x64apache-tomcat-9.0.45-windows-x64apache-tomcat-9.0.45-windows-x64apache-tomcat-9.0.45-windows-x64apache-tomcat-9.0.45-windows-x64apache-tomcat-9.0.45-windows-x64apache-...

    tomcat 源码分析系列文档

    【标题】"Tomcat源码分析系列文档"深入解析了Apache Tomcat服务器的内部工作原理,涵盖了一系列关键知识点,如HTTP协议、类加载机制、容器设计模式等。这些文档为理解Tomcat的运行机制提供了宝贵的资源。 【描述】...

    tomcat8-maven-plugin-3.0-r1655215.jar

    解决tomcat8-maven-plugin-3.0-r1655215.jar阿里云同有的问题。放到路径org\apache\tomcat\maven\tomcat8-maven-plugin\3.0-r1655215\就可以了

    tomcat-redis-session-manager源码

    《深入解析Tomcat-Redis-Session-Manager源码》 在现代Web应用中,服务器端会话管理是一个至关重要的部分,特别是在高并发、分布式环境中。Tomcat作为最流行的Java Servlet容器,提供了丰富的功能来支持这一需求。...

    Tomcat8亲测可用 tomcat-redis-session-manager的jar包

    描述中提到的“修改了tomcat-redis-session-manager源码进行的编译生成的jar包”,意味着这个jar包不是官方发布的原版,而是经过开发者对源代码进行了一些定制化的修改后重新编译得到的。这样的修改可能包括修复已知...

    tomcat7-maven-plugin-2.2.jar

    使用这个插件,我们可以通过简单的命令如`mvn tomcat7:run`来启动本地的Tomcat服务器,并自动部署我们的应用。对于开发者来说,这意味着可以快速地进行测试和调试,无需手动管理服务器环境。 然而,"修改版"通常...

    tomcat6-dta-ssl-1.0.0.jar

    tomcat6-dta-ssl-1.0.0.jar 此类文件将有助于tomcat支持ssl协议

    Tomcat源码apache-tomcat-8.5.47-src.zip

    `apache-tomcat-8.5.47-src.zip`这个压缩包包含了Tomcat 8.5.47版本的完整源代码,这对于想要研究Tomcat工作原理、优化性能或者进行自定义扩展的开发者非常有价值。 在开始学习Tomcat源码之前,首先需要了解一些...

    开发工具 apache-tomcat-8.0.41-windows-x86

    开发工具 apache-tomcat-8.0.41-windows-x86开发工具 apache-tomcat-8.0.41-windows-x86开发工具 apache-tomcat-8.0.41-windows-x86开发工具 apache-tomcat-8.0.41-windows-x86开发工具 apache-tomcat-8.0.41-...

    tomcat-redis-session-manager-master-2.0.0

    tomcat-redis-session-manager-2.0.0.jar jedis-2.5.2.jar commons-pool2-2.2.jar 2.修改 conf 目录下的 context.xml 文件 &lt;Valve className="com.orangefunction.tomcat.redissessions....

    tomcat-redis-session-manager的jar包-包含Tomcat7和Tomcat8

    《深入理解Tomcat-Redis-Session-Manager:在Tomcat7和Tomcat8中的应用》 在现代Web应用程序开发中,session管理是一个至关重要的环节,它涉及到用户会话的持久化和跨请求的数据共享。传统的session管理方式在高...

    TOMCAT源码分析(启动框架)

    【TOMCAT源码分析(启动框架)】 Tomcat是一款广泛应用的开源Java Servlet容器,它实现了Java Servlet和JavaServer Pages(JSP)规范,为Web应用程序提供了运行环境。本篇文章将深入探讨Tomcat的系统框架及其启动流程...

    tomcat共享session tomcat-redis-session-manager-2.0.0.jar包下载

    tomcat-redis-session-manager-2.0.0.jar包,不用自己打包了,tomcat共享session到redis中,解决分布式应用的状态问题。

    apache-tomcat-9.0.45-src

    apache-tomcat-9.0.45-srcapache-tomcat-9.0.45-srcapache-tomcat-9.0.45-srcapache-tomcat-9.0.45-srcapache-tomcat-9.0.45-srcapache-tomcat-9.0.45-srcapache-tomcat-9.0.45-srcapache-tomcat-9.0.45-srcapache-...

    apache-tomcat-6.0.35和apache-tomcat-6.0.35 src

    - Windows用户可以通过解压`apache-tomcat-6.0.35-windows-x86.zip`,运行`bin`目录下的批处理文件启动Tomcat。 - Linux或Mac用户需使用shell脚本启动Tomcat。 - 可以通过修改`conf/server.xml`配置文件来调整...

    apache-tomcat-11.0.0-M17-windows-x64.zip

    2. **解压与配置**:将`apache-tomcat-11.0.0-M17`文件夹解压到所需的目录,然后配置环境变量`CATALINA_HOME`指向该目录。 3. **启动与停止**:在Tomcat的`bin`目录下,可以通过执行`startup.bat`启动Tomcat,执行`...

    Tomcat7下载(apache-tomcat-7.0.85)

    Tomcat7下载(apache-tomcat-7.0.85)Tomcat7下载(apache-tomcat-7.0.85)Tomcat7下载(apache-tomcat-7.0.85)Tomcat7下载(apache-tomcat-7.0.85)

    tomcat8.5.20-redis-session共享-JAR包大全

    apache-tomcat-8.5.20.tar.gz源码包和context.xml文件,这套配置是我自己亲测可用的。。另外我用的redis4这个版本。注意:如果你使用的TOMCAT其他版本。例如tomcat6或者7这套JAR包可能不可用,tomcat8.0没有测试。...

    tomcat6-maven-plugin-2.1

    tomcat6-maven-plugin-2.1插件包

    tomcat-redis-session-manager for tomcat8.5

    文件名写错了,此压缩文件支持tomcat8.5。是否支持8.0请自行测试,本人只测试了8.5,可以使用。压缩文件包括tomcat-redis-session-manager-...apache-tomcat-8.5.33.tar.gz,nginx-1.6.2.tar.gz也打包进去,一步到位。

Global site tag (gtag.js) - Google Analytics