Tomcat源码走读 05-tomcat的容器初始化过程

05-tomcat的容器初始化过程

介绍容器初始化过程之前,让我们先来看下tomcat容器的类继承关系图。
在这里插入图片描述
Lifecycle:顶级接口:定义了添加,删除,查找生命周期监听器的方法,以及init,stop等。
MBeanRegistration:顶级接口,定义一些注册jmx其后的处理方法。
LifecycleBase: 成员LifecycleSupport作用是发布生命周期事件。定义了init,start,stop,destroy等方法的模板结构,这里主要是切换LifecycleState的状态,子类无需再自己考虑状态切换。只需要在xxxInternal()中实现自己的相关业务即可。
LifecycleMBeanBase: 在LifecycleBase的基础上添加了MBean的注册和注销逻辑,子类无需在考虑这些。
所以,我们大部分情况下只需要阅读子类的xxxInternal方法理解容器初始化过程。

TOMCAT容器初始化过程:

1. 从04-tomcat的server.xml解析中可以知道,catalina的load()加载中getServer().init();实际上就是StandardServer,上面也说了我们其实主要只需要看xxxInternal方法。StandardServer.initInternal()方法如下:

protected void initInternal() throws LifecycleException {
        super.initInternal();
        for (int i = 0; i < services.length; i++) {
            services[i].init();
        }
    }

2. StandardService.initInternal()

protected void initInternal() throws LifecycleException {
        super.initInternal();     
        if (container != null) {
            container.init();
        }
        // Initialize any Executors
        for (Executor executor : findExecutors()) {
            if (executor instanceof LifecycleMBeanBase) {
                ((LifecycleMBeanBase) executor).setDomain(getDomain());
            }
            executor.init();
        }
        // Initialize our defined Connectors
        synchronized (connectors) {
            for (Connector connector : connectors) {
                try {
                    connector.init();
                } catch (Exception e) {
                }
            }
        }
    }

3. 从server.xml解析中可以知道container就是StandardEngine。StandardEngine.initInternal()。

StandardEngine.initInternal()没有具体做什么只是调用的父类ContainerBase.initInternal()。

 protected void initInternal() throws LifecycleException {
        BlockingQueue<Runnable> startStopQueue =
            new LinkedBlockingQueue<Runnable>();
        startStopExecutor = new ThreadPoolExecutor(
                getStartStopThreadsInternal(),
                getStartStopThreadsInternal(), 10, TimeUnit.SECONDS,
                startStopQueue,
                new StartStopThreadFactory(getName() + "-startStop-")); //创建一个线程池,默认核心和最大线程数都是1.
        startStopExecutor.allowCoreThreadTimeOut(true);
        super.initInternal();
    }

4. executor.init(); 默认情况下没有executor。

5. connector.init();

这里以常用的8080端口为例,先看server.xml里面的配置:

<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />

通过ConnectorCreateRule.begin()解析上面的节点如下:

Connector con = new Connector(attributes.getValue("protocol"));
public Connector(String protocol) {
        setProtocol(protocol);
        try {
            Class<?> clazz = Class.forName(protocolHandlerClassName);
            this.protocolHandler = (ProtocolHandler) clazz.newInstance();
        } catch (Exception e) {
        }
    }
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);
            }
        }
    }

判断APR是否可用,关于APR具体描述请参考这个官方文档介绍Apache Portable Runtime (APR) based Native library for Tomcat
因为这里没有开启APR,所以protocolHandlerClassName = org.apache.coyote.http11.Http11Protocol。因此在Connector的构造方法里面会创建一个Http11Protocol的protocolHandler。

public Http11Protocol() {
        endpoint = new JIoEndpoint(); //创建一个JIoEndpoint
        cHandler = new Http11ConnectionHandler(this); //创建Http11ConnectionHandler
        ((JIoEndpoint) endpoint).setHandler(cHandler); //把cHandler 赋值给endPoint
        setSoLinger(Constants.DEFAULT_CONNECTION_LINGER);
        setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT);
        setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY);
    }

<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />

在通过SetAllPropertiesRule把后面的属性设置给Connector。

public boolean setProperty(String name, String value) {
        String repl = name;
        if (replacements.get(name) != null) {
            repl = replacements.get(name);
        }
        return IntrospectionUtils.setProperty(protocolHandler, repl, value);
    }

可以看到最后都设置给了protocolHandler。

看完了这些,让我们继续看connector.initInternal()方法:

protected void initInternal() throws LifecycleException {
        super.initInternal();
        adapter = new CoyoteAdapter(this);
        protocolHandler.setAdapter(adapter); //设置protocolHandler的adapter
        if( null == parseBodyMethodsSet ) {
            setParseBodyMethods(getParseBodyMethods());
        }
        if (protocolHandler.isAprRequired() &&
                !AprLifecycleListener.isAprAvailable()) {
            throw new LifecycleException(
                    sm.getString("coyoteConnector.protocolHandlerNoApr",
                            getProtocolHandlerClassName()));
        }
        try {
            protocolHandler.init(); //protocolHandler初始化
        } catch (Exception e) {
        }
        mapperListener.init(); //mapperListener初始化。
    }

6. protocolHandler.init(); ==》 AbstractProtocol.init() ==》 JIoEndpoint.init() ==> AbstractEndpoint.init()

public void init() throws Exception { //AbstractProtocol.init()
   。。。
        try {
            endpoint.init(); //endpoint就是上面创建的JIoEndpoint
        } catch (Exception ex) {
        }
    }

public final void init() throws Exception { //AbstractEndpoint.init()
        if (bindOnInit) {
            bind();
            bindState = BindState.BOUND_ON_INIT;
        }
    }

7. JIoEndpoint.bind()

public void bind() throws Exception {
        if (acceptorThreadCount == 0) {
            acceptorThreadCount = 1; //设置acceptorThreadCount =1
        }
        if (getMaxConnections() == 0) {
            setMaxConnections(getMaxThreadsExecutor(true)); //因为我们的server.xml里面没有配置executor。所以这里取得默认值 private int maxThreads = 200.
        }
        if (serverSocketFactory == null) {
            if (isSSLEnabled()) {
                serverSocketFactory =
                    handler.getSslImplementation().getServerSocketFactory(this);
            } else {
                serverSocketFactory = new DefaultServerSocketFactory(this); //创建serverSocket工厂
            }
        }
        if (serverSocket == null) {
            try {
                if (getAddress() == null) {
                    serverSocket = serverSocketFactory.createSocket(getPort(),
                            getBacklog()); //创建serversocket,实际调用的new ServerSocket (port, backlog)
                } else {
                    serverSocket = serverSocketFactory.createSocket(getPort(),
                            getBacklog(), getAddress());
                }
            } catch (BindException orig) {
            }
        }
    }

总结:
容器的初始化是从父容器依次向子容器进行的。
容器的jmx注册和注销等过程都抽取到父类中,子类无需再重复这些逻辑。
protocolHandler也就是本例中的http11protocol的属性值可以通过IntrospectionUtils.setProperty(protocolHandler, repl, value)设置,也就是通过在server.xml对应的Connector节点中指明相应的属性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值