tomcat源码分析(二)启动过程

在Catalina的load方法中,首先初始化Server组件。

  // Start the new server
        if (server instanceof Lifecycle) {
            try {
                server.initialize();
            } catch (LifecycleException e) {
                log.error("Catalina.start", e);
            }
        }

在StandardServer中初始化service

    public void initialize()
        throws LifecycleException
    {
        if (initialized) {
                log.info(sm.getString("standardServer.initialize.initialized"));
            return;
        }
        lifecycle.fireLifecycleEvent(INIT_EVENT, null);
        initialized = true;

        if( oname==null ) {
            try {
                oname=new ObjectName( "Catalina:type=Server");
                Registry.getRegistry(null, null)
                    .registerComponent(this, oname, null );
            } catch (Exception e) {
                log.error("Error registering ",e);
            }
        }

        // Register global String cache
        try {
            ObjectName oname2 =
                new ObjectName(oname.getDomain() + ":type=StringCache");
            Registry.getRegistry(null, null)
                .registerComponent(new StringCache(), oname2, null );
        } catch (Exception e) {
            log.error("Error registering ",e);
        }

        // Initialize our defined Services
        for (int i = 0; i < services.length; i++) {
            services[i].initialize();
        }
    }

在StandardService又初始化Connector

    public void initialize()
            throws LifecycleException
    {
        // Service shouldn‘t be used with embeded, so it doesn‘t matter
        if (initialized) {
            if(log.isInfoEnabled())
                log.info(sm.getString("standardService.initialize.initialized"));
            return;
        }
        initialized = true;

        if( oname==null ) {
            try {
                // Hack - Server should be deprecated...
                Container engine=this.getContainer();
                domain=engine.getName();
                oname=new ObjectName(domain + ":type=Service,serviceName="+name);
                this.controller=oname;
                Registry.getRegistry(null, null)
                    .registerComponent(this, oname, null);

                Executor[] executors = findExecutors();
                for (int i = 0; i < executors.length; i++) {
                    ObjectName executorObjectName =
                        new ObjectName(domain + ":type=Executor,name=" + executors[i].getName());
                    Registry.getRegistry(null, null)
                        .registerComponent(executors[i], executorObjectName, null);
                }

            } catch (Exception e) {
                log.error(sm.getString("standardService.register.failed",domain),e);
            }

        }
        if( server==null ) {
            // Register with the server
            // HACK: ServerFactory should be removed...

            ServerFactory.getServer().addService(this);
        }

        // Initialize our defined Connectors
        synchronized (connectors) {
                for (int i = 0; i < connectors.length; i++) {
                    connectors[i].initialize();
                }
        }
    }

我们从Connector的初始化方法开始看:

public void initialize()
        throws LifecycleException
    {
        if (initialized) {
            if(log.isInfoEnabled())
                log.info(sm.getString("coyoteConnector.alreadyInitialized"));
           return;
        }

        this.initialized = true;

        if( oname == null && (container instanceof StandardEngine)) {
            try {
                // we are loaded directly, via API - and no name was given to us
                StandardEngine cb=(StandardEngine)container;
                oname = createObjectName(cb.getName(), "Connector");
                Registry.getRegistry(null, null)
                    .registerComponent(this, oname, null);
                controller=oname;
            } catch (Exception e) {
                log.error( "Error registering connector ", e);
            }
            if(log.isDebugEnabled())
                log.debug("Creating name for connector " + oname);
        }

        // Initializa adapter
        adapter = new CoyoteAdapter(this);//创建一个适配器,该适配器会完成请求的真正处理
        protocolHandler.setAdapter(adapter);

        IntrospectionUtils.setProperty(protocolHandler, "jkHome",
                                       System.getProperty("catalina.base"));

        try {
            protocolHandler.init();//对于不同的协议,会有不同的ProtocolHandler实现类,我们来看Http11Protocol,它用来处理HTTP请求
        } catch (Exception e) {
            throw new LifecycleException
                (sm.getString
                 ("coyoteConnector.protocolHandlerInitializationFailed", e));
        }
    }

Http11Protocol的init()的核心代码

 public void init() throws Exception {
        endpoint.setName(getName());
        endpoint.setHandler(cHandler);
    ...
  try {
            endpoint.init();
        } catch (Exception ex) {
            log.error(sm.getString("http11protocol.endpoint.initerror"), ex);
            throw ex;
        }
}

endpoint的实现是JIoEndPoint

public void init()
        throws Exception {

        if (initialized)
            return;

        // Initialize thread count defaults for acceptor
    //默认处理线程数
        if (acceptorThreadCount == 0) {
            acceptorThreadCount = 1;
        }
    //得到服务端默认Socket即DefaultServerSocketFactory
        if (serverSocketFactory == null) {
            serverSocketFactory = ServerSocketFactory.getDefault();
        }
    //创建服务端Socket,为客户端请求做准备
        if (serverSocket == null) {
            try {
                if (address == null) {
                    serverSocket = serverSocketFactory.createSocket(port, backlog);
                } else {
                    serverSocket = serverSocketFactory.createSocket(port, backlog, address);
                }
            } catch (BindException be) {
                if (address == null)
                    throw new BindException(be.getMessage() + "<null>:" + port);
                else
                    throw new BindException(be.getMessage() + " " +
                            address.toString() + ":" + port);
            }
        }
        //if( serverTimeout >= 0 )
        //    serverSocket.setSoTimeout( serverTimeout );

        initialized = true;

    }

所有的加载工作已经完成了。接下来要启动这些组件了。

时间: 2024-07-31 07:41:15

tomcat源码分析(二)启动过程的相关文章

Tomcat源码分析二:先看看Tomcat的整体架构

Tomcat源码分析二:先看看Tomcat的整体架构 Tomcat架构图 我们先来看一张比较经典的Tomcat架构图: 从这张图中,我们可以看出Tomcat中含有Server.Service.Connector.Container等组件,接下来我们一起去大致的看看这些组件的作用和他们之间的相互联系.在这之前,我们先补充一个知识点,也就是Tomcat它实现的功能点是什么呢?通过查找一些资料,这里参考下极客时间<深入拆解Tomcat_Jetty>中的总结,即Tomcat 要实现 2 个核心功能:

Tomcat源码分析(二)--连接处理

?目标:在这篇文章希望搞明白http请求到tomcat后是怎么由连接器转交到容器的? 在上一节里已经启动了一个HttpConnector线程,并且也启动了固定数量的HttpProcessor线程.HttpConnector用来等待http连接,得到http连接后交给其中的一个HttpProcessor线程来处理.接下里具体看一下HttpConnector是怎么得到连接得,以及HttpProcessor是怎么处理的.当启动了HttpConnector线程后(在上一节已经知道怎么启动了),便在它的r

飞鸽传书源码分析-程序启动过程

转载请注明出处:http://blog.csdn.net/mxway/article/details/39581119 本文章是在飞鸽传书的2.06源码基础上分析 飞鸽传书源码运行流程如下,本篇文章只说明了飞鸽传书的启动过程,对于飞鸽伟书的消息机制及菜单加载等功能都不在本篇文章范围之内. 1. WinMain函数 int WINAPI WinMain(HINSTANCE hI, HINSTANCE, LPSTR cmdLine, int nCmdShow) { TMsgApp app(hI, c

workerman源码分析之启动过程

PHP一直以来以草根示人,它简单,易学,被大量应用于web开发,非常可惜的是大部分开发都在简单的增删改查,或者加上pdo,redis等客户端甚至分布式,以及规避语言本身的缺陷.然而这实在太委屈PHP了.记得有一次问walker,PHP能做什么?他说:什么都能做啊!当时我就震惊了,这怎么可能...直到后来一直看workerman源码,发现PHP原来有很多不为大家所知的诸多用法,包括多进程(还有线程).信号处理.namespace等等一大堆特点.而workerman正是这些很少被使用特性(或者说扩展

RabbitMQ源码分析 1. 启动过程

RabbitMQ的启动是基于boot steps, boot steps的每一个step可能是启动一个component,也可能是打印一个启动信息. boot steps是一个有向无环图,保证了启动的顺序性. 一个boot step: -rabbit_boot_step({recovery, [{description, "exchange, queue and binding recovery"}, {mfa,         {rabbit, recover, []}}, {req

Tomcat8源码分析3--Bootstrap启动过程

1. 执行Bootstrap类的static代码块, 初始化Bootstrap的catalinaHomeFile属性和catalinaBaseFile属性, 默认情况下值都为tomcat的安装目录. 关于这两个属性, 说明如下. ================================================== Advanced Configuration - Multiple Tomcat Instances =================================

Tomcat 源码分析(转)

Tomcat源码分析(一)--服务启动 1. Tomcat主要有两个组件,连接器和容器,所谓连接器就是一个http请求过来了,连接器负责接收这个请求,然后转发给容器.容器即servlet容器,容器有很多层,分别是Engine,     Host,Context,Wrapper.最大的容器Engine,代表一个servlet引擎,接下来是Host,代表一个虚拟机,然后是Context,代表一个应用,Wrapper对应一个servlet.从连接器     传过来连接后,容器便会顺序经过上面的容器,最

spring boot实战(第十五篇)嵌入tomcat源码分析

嵌入tomcat源码分析 在启动spring boot工程时利用@SpringBootApplication注解,该注解启动@EnableAutoConfiguration自动配置,加载META-INF/spring.factories文件 # Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.springframework.boot.autoconfigure.admin.Spri

Tomcat源码分析——启动与停止服务

前言 熟悉Tomcat的工程师们,肯定都知道Tomcat是如何启动与停止的.对于startup.sh.startup.bat.shutdown.sh.shutdown.bat等脚本或者批处理命令,大家一定知道改如何使用它,但是它们究竟是如何实现的,尤其是shutdown.sh脚本(或者shutdown.bat)究竟是如何和Tomcat进程通信的呢?本文将通过对Tomcat7.0的源码阅读,深入剖析这一过程. 由于在生产环境中,Tomcat一般部署在Linux系统下,所以本文将以startup.s

Tomcat源码分析之—具体启动流程分析

从Tomcat启动调用栈可知,Bootstrap类的main方法为整个Tomcat的入口,在init初始化Bootstrap类的时候为设置Catalina的工作路径也就是Catalina_HOME信息.Catalina.base信息,在initClassLoaders方法中初始化类加载器,然后通过反射初始化org.apache.catalina.startup.Catalina作为catalina守护进程: 一.load Bootstrap中load流程: 反射调用Catalina的load方法