TOMCAT架构浅析

TOMCAT架构浅析

前言

Tomcat是常用的Java Web服务器,HTTP请求在经过服务器之后,服务器会解析HTTP报文,将请求封装成Request对象,同时生成一个Response对象作为响应数据的载体。在平时的应用中,我们一般处理的是Request和Request对象,如何产生这两个对象对我们而言是透明的。本文旨在从整体上探究这一过程,浅析Tomcat架构与相关的技术细节。

TOMCAT架构

总览

下图是tomcat整体架构图:

TOMCAT架构浅析_第1张图片

  • Tomcat中最顶层的容器是Server,代表着整个服务器,一个tomcat对应一个server,整个 Tomcat 的生命周期由 Server 控制。

  • 一个Server中可以有多个Service,Service具体对外提供服务。

  • Service主要由Connector和Container组成,一个Service中包含一个Container和多个Connector。Connector用于接受请求并将请求封装成Request和Response来具体处理,Container用于封装和管理Servlet以及具体处理request请求。

Container部分

下图是容器架构图,包含4种子容器:

TOMCAT架构浅析_第2张图片

  • Engine:引擎,用来管理多个站点,一个Service最多只能有一个Engine。

  • Host:代表一个站点,也可以叫虚拟主机,通过配置Host就可以添加站点,Tomcat目录下webapps就是一个Host。

  • Context:代表一个应用程序,对应着平时开发的一套程序,webapps下每一个目录代表一个Context。

  • Wrapper:每一Wrapper封装着一个Servlet。

Tomcat服务器配置文件

在以上的基础上,对照着Tomcat配置文件server.xml可以看一下容器之间的关系。


# Server配置,最顶层标签

  
  
  
  
  

  
    
  

  # Service配置
  
  
    # 线程池配置
    
    
    

    

	# 容器配置,最上面的是引擎,一个Service只有一个
    
      
        
      

	   # 引擎下包含多个多个虚拟主机Host
      
        
        # 主机下包含多个项目Context
		 
      
    
  


Tomcat启动

Tomcat的组件是以嵌套的形式存在的,使用Tomcat实例时,启动脚本会执行引导类Bootstrap的main方法。所有组件实现了Lifecycle接口,该接口包含组件生命周期相关的方法,因此,当Tomcat启动时,会从最外层组件开始,嵌套调用内部组件的启动方法,以此启动所有组件。

Tomcat启动时序图如下图所示。

TOMCAT架构浅析_第3张图片

Tomcat处理请求

Tomcat启动之后,服务器等待请求进来处理请求。下图是Service处理请求流程图:

TOMCAT架构浅析_第4张图片

Connetor底层使用Socket接受TCP连接,将请求封装为Request和Response,再交由Container进行处理。Container处理完请求之后再返回给Connector,最后由Connector通过Socket将处理的结果返回给客户端。

Connector

  • Connector处理请求主要是通过ProtocolHandler进行的,不同的ProtocolHandler代表不同的连接类型。比如:Http11Protocol使用的是普通Socket来连接的,Http11NioProtocol使用的是NioSocket来连接的。

  • Connector.start()实际上会调用AbstractProtocol.start() 方法,最后调用endpoint.start() 的方法。AbstractProtocol是ProtocolHandler的抽象子类,AbstractProtocol包含了三个部件:Endpoint、Processor、Adapter。

1、以NioEndpoint为例,其启动逻辑源码分析如下:

public void startInternal() throws Exception {
  	...
  	
    // Create worker collection
    if (getExecutor() == null) {
        createExecutor();
    }

    initializeConnectionLatch();

    // 开始Poller线程
    poller = new Poller();
    Thread pollerThread = new Thread(poller, getName() + "-ClientPoller");
    pollerThread.setPriority(threadPriority);
    pollerThread.setDaemon(true);
    pollerThread.start();

    startAcceptorThread();//开始Accepter线程
}

2、Accepter用来处理底层Socket的网络连接,其run()方法摘取部分如下:

public void run() {
	...

    try {
        //如果到达最大连接数,等待
        endpoint.countUpOrAwaitConnection();

        // pause状态暂停接受连接
        if (endpoint.isPaused()) {
            continue;
        }

        U socket = null;
        try {
            // 接受socket连接
            socket = endpoint.serverSocketAccept();
        } catch (Exception ioe) {
            ...                
        }
        // Successful accept, reset the error delay
        errorDelay = 0;

        // Configure the socket
        if (endpoint.isRunning() && !endpoint.isPaused()) {
            // setSocketOptions() 方法会试图调用Processor处理socket
            if (!endpoint.setSocketOptions(socket)) {
                endpoint.closeSocket(socket);
            }
        } else {
            endpoint.destroySocket(socket);
        }
    } (Throwable t) {
    	...
    }
    ...
}

3、跟踪setSocketOptions,会将socket包装为SocketWrapper,注册到第一步创建的Poller对象中。

protected boolean setSocketOptions(SocketChannel socket) {
        // Process the connection
        try {
            // Disable blocking, polling will be used
            socket.configureBlocking(false);
            Socket sock = socket.socket();
            socketProperties.setProperties(sock);

            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, selectorPool, this);
                } else {
                    channel = new NioChannel(bufhandler);
                }
            } else {
            }
            NioSocketWrapper socketWrapper = new NioSocketWrapper(channel, this);
            channel.reset(socket, socketWrapper);
            socketWrapper.setReadTimeout(getConnectionTimeout());
            socketWrapper.setWriteTimeout(getConnectionTimeout());
            socketWrapper.setKeepAliveLeft(NioEndpoint.this.getMaxKeepAliveRequests());
            socketWrapper.setSecure(isSSLEnabled());
            poller.register(channel, socketWrapper);
            return true;
        } catch (Throwable t) {
            ExceptionUtils.handleThrowable(t);
            try {
                log.error(sm.getString("endpoint.socketOptionsError"), t);
            } catch (Throwable tt) {
                ExceptionUtils.handleThrowable(tt);
            }
        }
        // Tell to close the socket
        return false;
    }

4、Poller是一个Runnable对象,最后调用processKey方法处理请求,其run()摘取方法如下:

public void run() {
    // 循环直到destroy()被调用
    while (true) {
			...		
        Iterator iterator =
            keyCount > 0 ? selector.selectedKeys().iterator() : null;
        // 遍历已经就绪的事件,分发
        while (iterator != null && iterator.hasNext()) {
            SelectionKey sk = iterator.next();
            NioSocketWrapper socketWrapper = (NioSocketWrapper) sk.attachment();
            if (socketWrapper == null) {
                iterator.remove();
            } else {
                iterator.remove();
                processKey(sk, socketWrapper);//处理连接
            }
        }
        ...
}

5、processKey方法调用processSocket方法处理,部分源码摘取如下:

public boolean processSocket(SocketWrapperBase socketWrapper,
            SocketEvent event, boolean dispatch) {
    try {
        if (socketWrapper == null) {
            return false;
        }
        SocketProcessorBase sc = null;
        if (processorCache != null) {
            sc = processorCache.pop();
        }
        if (sc == null) {
        	//创建Socket处理器,也是一个Runnable对象
            sc = createSocketProcessor(socketWrapper, event);
        } else {
            sc.reset(socketWrapper, event);
        }
        Executor executor = getExecutor();
        if (dispatch && executor != null) {
            executor.execute(sc);
        } else {
            sc.run();
        }
    } 
    ...
}

6、在SocketProcessor中,最后会调用getHandler().process(args)。其中Handler是AbstractEndpoint.Handler接口,其实现类是AbstractProtocol的内部类ConnectionHandler

ConnectionHandler维护了Map的键值对,如果对应的Socket找不到处理器,则会创建处理器,保存起来。
最终调用的是 processor.process(wrapper, status);

7、接下来的方法实际调用了AbstractProcessorLight.service(),以其子类方法Http11Processor.service()为例,最后调用getAdapter().service(request, response) 处理,即使用适配器处理封装后的请求。

在Connector最后封装的对象是org.apache.coyote.Request和org.apache.coyote.Response。

8、在适配器的service方法中,请求从Connector被转到Container。部分源码片段如下:

 public void service(org.apache.coyote.Request req, org.apache.coyote.Response res)
            throws Exception {
		// 将org.apache.coyote.Request转化为org.apache.catalina.connector.Request,Response同理
        Request request = (Request) req.getNote(ADAPTER_NOTES);
        Response response = (Response) res.getNote(ADAPTER_NOTES);

        if (request == null) {
            // Create objects
            request = connector.createRequest();
            request.setCoyoteRequest(req);
            response = connector.createResponse();
            response.setCoyoteResponse(res);

            // Link objects
            request.setResponse(response);
            response.setRequest(request);

            // Set as notes
            req.setNote(ADAPTER_NOTES, request);
            res.setNote(ADAPTER_NOTES, response);

            // Set query string encoding
            req.getParameters().setQueryStringCharset(connector.getURICharset());
        }

        if (connector.getXpoweredBy()) {
            response.addHeader("X-Powered-By", POWERED_BY);
        }

        boolean async = false;
        boolean postParseSuccess = false;

        req.getRequestProcessor().setWorkerThreadName(THREAD_NAME.get());

        try {
            // Parse and set Catalina and configuration specific
            // request parameters
            postParseSuccess = postParseRequest(req, request, res, response);
            if (postParseSuccess) {
                //check valves if we support async
                request.setAsyncSupported(
                        connector.getService().getContainer().getPipeline().isAsyncSupported());
                //调用容器管道链发送请求,最终会被Servlet处理
                connector.getService().getContainer().getPipeline().getFirst().invoke(
                        request, response);
            }
            ...
       }
}   

Container

  • Container是容器的父接口,所有子容器都必须实现这个接口,其设计用的是典型的责任链的的设计模式。

  • 每一个容器内部都有一个对应的管道Pipeline,管道管理对应的阀门Valve。每一种容器都对应一种Valve,StandardEngine、StandardHost、StandardContext、StandardWrapper分别对应StandardEngineValve、StandardHostValve、StandardContextValve、StandardWrapperValve。在容器初始化时,每一个容器都会初始化对应的Pipeline和Valve。

  • Connector在接收到请求后会首先调用最顶层容器的Pipeline来处理,处理方法为StandardEngineValve.invoke(request, response)。

  • Engine->Host->Context->Wrapper对应的Valve依次调用,最后由StandardWrapperValve获取对应的StandardWrapper,最终拿到对应的Servlet。

  • 创建FilterChain,调用Servlet的service()方法。

  • 当所有的Pipeline-Value都执行完之后,将结果交给Connector,通过Socket的方式将结果返回给客户端。


参考博文:https://blog.csdn.net/qq_38245537/article/details/79009448

你可能感兴趣的:(JAVA)