深入学习Tomcat8.5

  源码地址:https://gitee.com/yangaizy/my-tomcat8.5

学习tomcat这类有配置文件的源码时,可以从配置文件上看整体架构然后进去学习源码。

一 tomcat架构概览

1.架构图:

二、tomcat生命周期

1.LifeCycle类

 *            start()
 *  -----------------------------
 *  |                           |
 *  | init()                    |
 * NEW -»-- INITIALIZING        |
 * | |           |              |     ------------------«-----------------------
 * | |           |auto          |     |                                        |
 * | |          \|/    start() \|/   \|/     auto          auto         stop() |
 * | |      INITIALIZED --»-- STARTING_PREP --»- STARTING --»- STARTED --»---  |
 * | |         |                                                            |  |
 * | |destroy()|                                                            |  |
 * | --»-----«--    ------------------------«--------------------------------  ^
 * |     |          |                                                          |
 * |     |         \|/          auto                 auto              start() |
 * |     |     STOPPING_PREP ----»---- STOPPING ------»----- STOPPED -----»-----
 * |    \|/                               ^                     |  ^
 * |     |               stop()           |                     |  |
 * |     |       --------------------------                     |  |
 * |     |       |                                              |  |
 * |     |       |    destroy()                       destroy() |  |
 * |     |    FAILED ----»------ DESTROYING ---«-----------------  |
 * |     |                        ^     |                          |
 * |     |     destroy()          |     |auto                      |
 * |     --------»-----------------    \|/                         |
 * |                                 DESTROYED                     |
 * |                                                               |
 * |                            stop()                             |
 * ----»-----------------------------»------------------------------
 *

2.LifecycleBase

运用模版方法设计模式定义了上图的start,stop,init,destroy等方法

3.LifecycleMBeanBase

定义了将tomcat组件注册到jmx中的方法。

4.ContainerBase


添加子容器方法:addChild

该方法被digester的createStartDigester方法解析配置文件时调用。

org.apache.catalina.startup.HostRuleSet#addRuleInstances

作为LifeCycleBase的子类,会实现xxInterval(xx为start,init等)方法用于生命周期处理。

threadStart(启动后台线程)

org.apache.catalina.core.ContainerBase#threadStart

// -------------------- Background Thread --------------------

    /**
     * Start the background thread that will periodically check for session timeouts.
     */
    protected void threadStart() {

        if (thread != null) {
            return;
        }
        //只有设置了后台线程间隔才会启动后台线程
        if (backgroundProcessorDelay <= 0) {
            return;
        }

        threadDone = false;
        String threadName = "ContainerBackgroundProcessor[" + toString() + "]";
        thread = new Thread(new ContainerBackgroundProcessor(), threadName);
        thread.setDaemon(true);
        thread.start();

    }

只有设置了后台线程间隔才会启动后台线程处理任务

org.apache.catalina.core.ContainerBase.ContainerBackgroundProcessor#processChildren

子容器如果没有设置后台线程间隔,父容器会帮忙解决

org.apache.catalina.Container#backgroundProcess

给容器自己实现的,用于处理周期性任务。

5.LifeCycleListener

生命周期事件监听器

lifecycleEvent

org.apache.catalina.LifecycleListener#lifecycleEvent

用于处理特定的生命周期事件方法

三、Tomcat应用启动

Bootstrap启动

BootStrap的main方法是整个tomcat的入口。其init方法创建了真正干活的是由单独的类加载器反射而来的Catalina类:

public void init() throws Exception {

        initClassLoaders();

        Thread.currentThread().setContextClassLoader(catalinaLoader);

        SecurityClassLoad.securityClassLoad(catalinaLoader);

        // Load our startup class and call its process() method
        if (log.isDebugEnabled()) {
            log.debug("Loading startup class");
        }
        Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
        Object startupInstance = startupClass.getConstructor().newInstance();

        // Set the shared extensions class loader
        if (log.isDebugEnabled()) {
            log.debug("Setting startup class properties");
        }
        String methodName = "setParentClassLoader";
        Class<?> paramTypes[] = new Class[1];
        paramTypes[0] = Class.forName("java.lang.ClassLoader");
        Object paramValues[] = new Object[1];
        paramValues[0] = sharedLoader;
        Method method =
            startupInstance.getClass().getMethod(methodName, paramTypes);
        method.invoke(startupInstance, paramValues);

        catalinaDaemon = startupInstance;
    }

Catalina重点是load和start方法:

3.catalina不一定需要存在,因为catalina的主要作用还是就是解析server.xml初始化组件(包含容器)树,然后调用start方法启动server,

四:类加载器相关:

BootStap初始化得到的三个类加载器都是一样的:

Catalina的父加载器是图上的sharedLoader

五:Server组件:

org.apache.catalina.core.StandardServer

核心方法:

addService

await:

org.apache.catalina.core.StandardServer#await

设置一个socket连接等待远程关闭指令。

initInternal

org.apache.catalina.core.StandardServer#initInternal

六:connector组件

org.apache.catalina.connector.Connector

public Connector(String protocol) {
        setProtocol(protocol);
        // Instantiate protocol handler
        //重点
        ProtocolHandler p = null;
        try {
            Class<?> clazz = Class.forName(protocolHandlerClassName);
            p = (ProtocolHandler) clazz.getConstructor().newInstance();
        } catch (Exception e) {
            log.error(sm.getString("coyoteConnector.protocolHandlerInstantiationFailed"), e);
        } finally {
            this.protocolHandler = p;
        }

        if (Globals.STRICT_SERVLET_COMPLIANCE) {
            uriCharset = StandardCharsets.ISO_8859_1;
        } else {
            uriCharset = StandardCharsets.UTF_8;
        }

        // Default for Connector depends on this (deprecated) system property
        if (Boolean
                .parseBoolean(System.getProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "false"))) {
            encodedSolidusHandling = EncodedSolidusHandling.DECODE;
        }
    }

Connector的startInterval中启动了ProtocalHandler:

protected void startInternal() throws LifecycleException {

        // Validate settings before starting
        if (getPortWithOffset() < 0) {
            throw new LifecycleException(
                    sm.getString("coyoteConnector.invalidPort", Integer.valueOf(getPortWithOffset())));
        }

        setState(LifecycleState.STARTING);

        try {
            protocolHandler.start();
        } catch (Exception e) {
            throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerStartFailed"), e);
        }
    }

ProtocalHandler的重点方法:

子类:AbstractProtocol

构造函数
public AbstractProtocol(AbstractEndpoint<S, ?> endpoint) {
        this.endpoint = endpoint;
        ConnectionHandler<S> cHandler = new ConnectionHandler<>(this);
        setHandler(cHandler);
        getEndpoint().setHandler(cHandler);
        setSoLinger(Constants.DEFAULT_CONNECTION_LINGER);
        setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY);
    }
start方法:
public void start() throws Exception {
        if (getLog().isInfoEnabled()) {
            getLog().info(sm.getString("abstractProtocolHandler.start", getName()));
            logPortOffset();
        }

        endpoint.start();

        // Start timeout thread
        asyncTimeout = new AsyncTimeout();
        Thread timeoutThread = new Thread(asyncTimeout, getNameInternal() + "-AsyncTimeout");
        int priority = endpoint.getThreadPriority();
        if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) {
            priority = Thread.NORM_PRIORITY;
        }
        timeoutThread.setPriority(priority);
        timeoutThread.setDaemon(true);
        timeoutThread.start();
    }

子类:AbstractHttp11Protocol

构造函数
public AbstractHttp11Protocol(AbstractEndpoint<S,?> endpoint) {
        super(endpoint);
        setConnectionTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT);
    }

由此可见tomcat超时时间设置为60s.

createProcessor 创建关于Http协议处理的处理器
Override
    protected Processor createProcessor() {
        Http11Processor processor = new Http11Processor(this, getEndpoint());
        processor.setAdapter(getAdapter());
        processor.setMaxKeepAliveRequests(getMaxKeepAliveRequests());
        processor.setConnectionUploadTimeout(getConnectionUploadTimeout());
        processor.setDisableUploadTimeout(getDisableUploadTimeout());
        processor.setRestrictedUserAgents(getRestrictedUserAgents());
        processor.setMaxSavePostSize(getMaxSavePostSize());
        return processor;
    }

子类Http11NioProtocol

仅仅添加了(“http-nio”)名字前缀。

成员AbstractEndpoint

setMaxConnections
private int maxConnections = 8*1024;
    public void setMaxConnections(int maxCon) {
        this.maxConnections = maxCon;
        LimitLatch latch = this.connectionLimitLatch;
        if (latch != null) {
            // Update the latch that enforces this
            if (maxCon == -1) {
                releaseConnectionLatch();
            } else {
                latch.setLimit(maxCon);
            }
        } else if (maxCon > 0) {
            initializeConnectionLatch();
        }
    }
用于处理的maxConnection的限流工具LimitLatch :
/**
 * counter for nr of connections handled by an endpoint
 */
private volatile LimitLatch connectionLimitLatch = null;

成员NioEndpoint

startInternal

启动方法,创建线程池,启动监听客户端线程Acceptor

/**
     * Start the NIO endpoint, creating acceptor, poller threads.
     */
    @Override
    public void startInternal() throws Exception {

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

            if (socketProperties.getProcessorCache() != 0) {
                processorCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                        socketProperties.getProcessorCache());
            }
            if (socketProperties.getEventCache() != 0) {
                eventCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                        socketProperties.getEventCache());
            }
            if (socketProperties.getBufferPool() != 0) {
                nioChannels = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                        socketProperties.getBufferPool());
            }

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

            initializeConnectionLatch();

            // Start poller thread
            poller = new Poller();
            Thread pollerThread = new Thread(poller, getName() + "-Poller");
            pollerThread.setPriority(threadPriority);
            pollerThread.setDaemon(true);
            pollerThread.start();

            startAcceptorThread();
        }
    }
org.apache.tomcat.util.net.Acceptor#run

该方法负责处理客户端的链接请求

setSocketOptions

设置和客户端相连socket信息以及将已经建立连接的socket包装成pollerEvent给Poller线程处理

protected boolean setSocketOptions(SocketChannel socket) {
        NioSocketWrapper socketWrapper = null;
        try {
            // Allocate channel and wrapper
            NioChannel channel = null;
            if (nioChannels != null) {
                channel = nioChannels.pop();
            }
            if (channel == null) {
                //是用户态读写缓冲区
                SocketBufferHandler bufhandler = new SocketBufferHandler(
                        socketProperties.getAppReadBufSize(),
                        socketProperties.getAppWriteBufSize(),
                        socketProperties.getDirectBuffer());
                if (isSSLEnabled()) {
                    channel = new SecureNioChannel(bufhandler, this);
                } else {
                    channel = new NioChannel(bufhandler);
                }
            }
            NioSocketWrapper newWrapper = new NioSocketWrapper(channel, this);
            channel.reset(socket, newWrapper);
            connections.put(socket, newWrapper);
            socketWrapper = newWrapper;

            // Set socket properties
            // Disable blocking, polling will be used
            socket.configureBlocking(false);
            socketProperties.setProperties(socket.socket());

            socketWrapper.setReadTimeout(getConnectionTimeout());
            socketWrapper.setWriteTimeout(getConnectionTimeout());
            socketWrapper.setKeepAliveLeft(NioEndpoint.this.getMaxKeepAliveRequests());
            poller.register(socketWrapper);
            return true;
        } catch (Throwable t) {
            ExceptionUtils.handleThrowable(t);
            try {
                log.error(sm.getString("endpoint.socketOptionsError"), t);
            } catch (Throwable tt) {
                ExceptionUtils.handleThrowable(tt);
            }
            if (socketWrapper == null) {
                destroySocket(socket);
            }
        }
        // Tell to close the socket if needed
        return false;
    }

给和客户端连接设置tcp参数的方法是:

org.apache.tomcat.util.net.SocketProperties#setProperties(java.net.Socket)

七、Tomcat NIo 操作

Tomcat Nio核心组件:

Poller

用来处理accept后的socket相关事件

其包含了PollerEvent的events看似是无界队列,实则由LimitLatch的大小限制。

run方法

org.apache.tomcat.util.net.NioEndpoint.Poller#run

处理PollerEvent事件以及发现io事件

processSocket

org.apache.tomcat.util.net.AbstractEndpoint#

将待读写的socket事件包装成SocketProcessor丢给线程池

SocketProcessor

用于真正处理io事件,io事件被poller线程丢给SocketProcessor,然后被线程池执行。

doRun()

org.apache.tomcat.util.net.NioEndpoint.SocketProcessor#doRun

处理基本信息然后把数据交给ConnectionHandler处理

ConnectionHandler

process
 

org.apache.coyote.AbstractProtocol.ConnectionHandler#process

处理基本信息然后把数据交给AbstractProcessorLight处理

AbstractProcessorLight

process

org.apache.coyote.AbstractProcessorLight#process

定义了处理http请求的基本操作,调用子类的service方法

Http11Processor

HttpParser类

用于处理http协议解析

Request、Response类

原生请求、响应

service()

org.apache.coyote.http11.Http11Processor#service

用于处理http header然后调用CoyoteAdapter适配成容器需要的请求头和响应头

CoyoteAdapter

service()

org.apache.catalina.connector.CoyoteAdapter#service

用于将原生request适配成引擎层需要的httprequest,然后传输到engine层

八、Engine(StandardEngine类)

继承自ContainerBase的生命周期方法(start,init,stop...)

构造函数:

org.apache.catalina.core.StandardEngine#StandardEngine

初始化了Pipeline的basic。

EnginConfig

engine生命周期监听器

九、Pipeline(StandardPipeline)

Pipeline概述:

主要负责了valve的增删改查

basic是最重要的valve

每个容器默认就带有了Pipeline:

pipeline和容器互相持有引用。

Valve

invoke是Valve子类执行相关任务的关键。

ErrorReportValve

org.apache.catalina.valves.ErrorReportValve#invoke

这个valve用来记录错误信息并输出。

十、Tomcat重要方法类

SystemLogHandler

public SystemLogHandler(PrintStream wrapped) {
        super(wrapped);
        out = wrapped;
    }
protected void initStreams() {
        // Replace System.out and System.err with a custom PrintStream
        System.setOut(new SystemLogHandler(System.out));
        System.setErr(new SystemLogHandler(System.err));
    }

可用于重定向输出流,也可以说是捕获了输出,实现原理是重写PrintStream的方法。

/**
     * Find PrintStream to which the output must be written to.
     * @return the print stream
     */
    protected PrintStream findStream() {
        Queue<CaptureLog> stack = logs.get();
        if (stack != null && !stack.isEmpty()) {
            CaptureLog log = stack.peek();
            if (log != null) {
                PrintStream ps = log.getStream();
                if (ps != null) {
                    return ps;
                }
            }
        }
        return out;
    }

WebappLoader

十一、Host

继承自ContainerBase的生命周期方法(start,init,stop...)

HostConfig

lifecycleEvent

org.apache.catalina.startup.HostConfig#lifecycleEvent

deployApps

org.apache.catalina.startup.HostConfig#deployApps()

/**
     * Deploy applications for any directories or WAR files that are found
     * in our "application root" directory.
     */
    protected void deployApps() {
        File appBase = host.getAppBaseFile();
        File configBase = host.getConfigBaseFile();
        String[] filteredAppPaths = filterAppPaths(appBase.list());
        // Deploy XML descriptors from configBase
        deployDescriptors(configBase, configBase.list());
        // Deploy WARs
        deployWARs(appBase, filteredAppPaths);
        // Deploy expanded folders
        deployDirectories(appBase, filteredAppPaths);
    }

部署context应用以及热部署

org.apache.catalina.startup.HostConfig#deployDescriptor

十二、Context

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值