阅读 146

Tomcat源码解析之Web请求与处理

Tomcat源码解析之Web请求与处理

这篇文章主要介绍了Tomcat源码解析之Web请求与处理,文中有非常详细的代码示例,对正在学习java的小伙伴们有很好的帮助,需要的朋友可以参考下

前言

Tomcat最全UML类图

在这里插入图片描述

Tomcat请求处理过程:

在这里插入图片描述

Connector对象创建的时候,会创建Http11NioProtocol的ProtocolHandler,在Connector的startInteral方法中,会启动AbstractProtocol,AbstractProtocol启动NioEndPoint进行监听客户端的请求,EndPoint接受到客户端的请求之后,会交给Container去处理请求。请求从Engine开始经过的所有容器都含有责任链模式,每经过一个容器都会调用该容器的责任链对请求进行处理。

在这里插入图片描述

一、EndPoint

在这里插入图片描述

默认的EndPoint实现是NioEndPoint,NioEndPoint有四个内部类,分别是Poller、Acceptor、PollerEvent、SocketProcessor、NioSocketWrapper。

(1)Acceptor负责监听用户的请求,监听到用户请求之后,调用getPoller0().register(channel);先将当前请求封装成PollerEvent,new PollerEvent(socket, ka, OP_REGISTER); 将当前请求,封装成注册事件,并添加到PollerEvent队列中,然后将PollerEvent注册到Poller的Selector对象上面。

(2)Poller线程会一直遍历可以处理的事件(netty的selestor),当找到需要处理的事件之后,调用processKey(sk, socketWrapper);对,执行要处理的PollerEvent的run方法,对请求进行处理。

(3)PollerEvent继承自Runnable接口,在其run方法里面,如果是PollerEvent的事件是注册OP_REGISTER,那么就将当前的socket注册到Poller的selector上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public void run() {
           if (interestOps == OP_REGISTER) {
               try {
                   // 核心代码,终于找到了!!!!!
                   // 当事件是注册的时候,将当前的NioSocketChannel注册到Poller的Selector上。
                   socket.getIOChannel().register(
                           socket.getPoller().getSelector(), SelectionKey.OP_READ, socketWrapper);
               } catch (Exception x) {
                   log.error(sm.getString("endpoint.nio.registerFail"), x);
               }
           } else {
               final SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector());
               try {
                   if (key == null) {
 
                       // The key was cancelled (e.g. due to socket closure)
                       // and removed from the selector while it was being
                       // processed. Count down the connections at this point
                       // since it won't have been counted down when the socket
                       // closed.
                       // SelectionKey被取消的时候需要将SelectionKey对应的EndPoint的Connection计数器,减一
                       socket.socketWrapper.getEndpoint().countDownConnection();
                       ((NioSocketWrapper) socket.socketWrapper).closed = true;
                   } else {
                       final NioSocketWrapper socketWrapper = (NioSocketWrapper) key.attachment();
                       if (socketWrapper != null) {
                           //we are registering the key to start with, reset the fairness counter.
                           int ops = key.interestOps() | interestOps;
                           socketWrapper.interestOps(ops);
                           key.interestOps(ops);
                       } else {
                           socket.getPoller().cancelledKey(key);
                       }
                   }
               } catch (CancelledKeyException ckx) {
                   try {
                       socket.getPoller().cancelledKey(key);
                   } catch (Exception ignore) {
                   }
               }
           }
       }

(4)Poller线程内会执行keyCount = selector.select(selectorTimeout);获取当前需要处理的SelectionKey的数量,然后当keyCount大于0时,会获取selector的迭代器,遍历所有需要的selectionkey,并对其进行处理。在这里将socket的事件封装成NioSocketWrapper。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 得到selectedKeys的迭代器
Iterator<SelectionKey> iterator =
         keyCount > 0 ? selector.selectedKeys().iterator() : null;
 
 // 遍历所有的SelectionKey,并对其进行处理
 while (iterator != null && iterator.hasNext()) {
     SelectionKey sk = iterator.next();
     iterator.remove();
     NioSocketWrapper socketWrapper = (NioSocketWrapper) sk.attachment();
     // Attachment may be null if another thread has called
     // cancelledKey()
     // 如果有attachment,就处理
     if (socketWrapper != null) {
         // 处理事件
         processKey(sk, socketWrapper);
     }
 }

processKey在处理SelectionKey,如果当前Poller已经关闭,就取消key。SelectionKey对应的Channel如果发生读事件,就调用AbatractEndPoint.processSocket执行读操作processSocket(attachment, SocketEvent.OPEN_READ, true),如果SelectionKey对应的Channel发生写事件,就执行processSocket(attachment, SocketEvent.OPEN_WRITE, true);读大于写。socket的事件处理调用的是AbatractEndPoint的processSocket方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
protected void processKey(SelectionKey sk, NioSocketWrapper attachment) {
         try {
             if (close) {
                 // 如果Poller已经关闭了,就取消key
                 cancelledKey(sk);
             } else if (sk.isValid() && attachment != null) {
                 if (sk.isReadable() || sk.isWritable()) {
                     if (attachment.getSendfileData() != null) {
                         processSendfile(sk, attachment, false);
                     } else {
                         unreg(sk, attachment, sk.readyOps());
                         boolean closeSocket = false;
                         // Read goes before write
                         // 读优于写
                         // 如果SelectionKey对应的Channel已经准备好了读
                         // 就对NioSocketWrapper进行读操作
                         if (sk.isReadable()) {
                             if (!processSocket(attachment, SocketEvent.OPEN_READ, true)) {
                                 closeSocket = true;
                             }
                         }
                         // 如果SelectionKey对应的Channel已经准备好了写
                         // 就对NioSocketWrapper进行写操作
                         if (!closeSocket && sk.isWritable()) {
                             if (!processSocket(attachment, SocketEvent.OPEN_WRITE, true)) {
                                 closeSocket = true;
                             }
                         }
                         if (closeSocket) {
                             // 如果已经关闭了,就取消key
                             cancelledKey(sk);
                         }
                     }
                 }
                  
}

AbatractEndPoint.processSocket方法首先从缓存中获取SocketProcessor类,如果缓存中没有就创建一个,SocketProcessorBase接口对应的就是NioEndPoint.SocketProcessor,也就是Worker。将对应的SocketProcessor类放入到线程池中执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public boolean processSocket(SocketWrapperBase<S> socketWrapper,
                                SocketEvent event, boolean dispatch) {
 
   // 得到socket的处理器
   // Connector在构造函数里面已经指定了协议:org.apache.coyote.http11.Http11NioProtocol。
   SocketProcessorBase<S> sc = processorCache.pop();
   if (sc == null) {
   // 如果没有,就创建一个Socket的处理器。创建的时候指定socketWrapper以及socket的事件。
       sc = createSocketProcessor(socketWrapper, event);
   } else {
       sc.reset(socketWrapper, event);
   }
   //socket的处理交给了线程池去处理。
   Executor executor = getExecutor();
   if (dispatch && executor != null) {
       executor.execute(sc);
   } else {
       sc.run();
   }

(5)NioEndPoint.NioSocketWrapper,是Socket的封装类,增强类,将Socket与其他对象建立关联。

1
2
3
4
5
6
7
8
9
10
11
public static class NioSocketWrapper extends SocketWrapperBase<NioChannel> {
       private final NioSelectorPool pool;
 
       private Poller poller = null; // 轮询的Poller
       private int interestOps = 0;
       private CountDownLatch readLatch = null;
       private CountDownLatch writeLatch = null;
       private volatile SendfileData sendfileData = null;
       private volatile long lastRead = System.currentTimeMillis();
       private volatile long lastWrite = lastRead;
       private volatile boolean closed = false;

(6)NioEndPoint.SocketProcessor(Worker)继承了Runnable接口,负责对socket的g各种事件进行处理。读事件、写事件、停止时间、超时事件、断连事件、错误时间、连接失败事件。

在这里插入图片描述

SocketProcessor的doRun方法,会根据SocketState进行处理,SocketState 为STOP、DISCONNECT或者ERROR的时候就进行关闭,SocketWrapperBase对应的selector事件,得到指定的Handler处理器进行处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
@Override
 protected void doRun() {
     NioChannel socket = socketWrapper.getSocket();
     SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector());
 
     try {
         int handshake = -1;
 
         try {
             if (key != null) {
                 if (socket.isHandshakeComplete()) {
                     // 是否已经握手成功,不需要TLS(加密)握手,就让处理器对socket和event的组合进行处理。
                     handshake = 0;
                 } else if (event == SocketEvent.STOP || event == SocketEvent.DISCONNECT ||
                         event == SocketEvent.ERROR) {
                     // 不能够完成TLS握手,就把他认为是TLS握手失败。
                     handshake = -1;
                 } else {
                     handshake = socket.handshake(key.isReadable(), key.isWritable());
                     // The handshake process reads/writes from/to the
                     // socket. status may therefore be OPEN_WRITE once
                     // the handshake completes. However, the handshake
                     // happens when the socket is opened so the status
                     // must always be OPEN_READ after it completes. It
                     // is OK to always set this as it is only used if
                     // the handshake completes.
                     // 握手从/向socket读/写时,握手一旦完成状态应该为OPEN_WRITE,
                     // 握手是在套接字打开时发生的,因此在完成后状态必须始终为OPEN_READ
                     // 始终设置此选项是可以的,因为它仅在握手完成时使用。
                     event = SocketEvent.OPEN_READ;
                 }
             }
         } catch (IOException x) {
             handshake = -1;
             if (log.isDebugEnabled()) log.debug("Error during SSL handshake", x);
         } catch (CancelledKeyException ckx) {
             handshake = -1;
         }
         if (handshake == 0) {
             SocketState state = SocketState.OPEN;
             // Process the request from this socket
             if (event == null) {
                 // 调用处理器进行处理。
                 // NioEndPoint的默认Handler是Http11的
                 // 这里的Handler是AbstractProtocol.ConnectionHandler
                 // 这个Handler的设置方法是:
                 // 首先在Connector类的构造函数中,将默认的ProtocolHandler设置为org.apache.coyote.http11.Http11NioProtocol
                 // AbstractHttp11Protocol的构造函数里面创建了Handler类ConnectionHandler
                 state = getHandler().process(socketWrapper, SocketEvent.OPEN_READ);
             } else {
                 state = getHandler().process(socketWrapper, event);
             }
             // 如果返回的状态是SocketState,那么就关掉连接
             if (state == SocketState.CLOSED) {
                 close(socket, key);
             }
         } else if (handshake == -1) {
             getHandler().process(socketWrapper, SocketEvent.CONNECT_FAIL);
             close(socket, key);
         } else if (handshake == SelectionKey.OP_READ) {
             // 如果是SelectionKey.OP_READ,也就是读事件的话,就将OP_READ时间设置到socketWrapper
             socketWrapper.registerReadInterest();
         } else if (handshake == SelectionKey.OP_WRITE) {
             // 如果是SelectionKey.OP_WRITE,也就是读事件的话,就将OP_WRITE事件设置到socketWrapper
             socketWrapper.registerWriteInterest();
         }

二、ConnectionHandler

在这里插入图片描述

(1)ConnectionHandler用于根据Socket连接找到相应的Engine处理器。

上面是SocketProcessor的doRun方法,执行了getHandler().process(socketWrapper, SocketEvent.OPEN_READ);;process方法是首先在Map缓存中查找当前socket是否存在对应的processor,如果不存在,再去可循环的处理器栈中查找是否存在,如果不存在就创建相应的Processor,然后将新创建的Processor与Socket建立映射,存在connection的Map中。在任何一个阶段得到Processor对象之后,会执行processor的process方法state = processor.process(wrapper, status);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125