23년 5월에 작성한 글입니다.
SocketChannel
) 을 생성하고 해당 커넥션에 대한 프로세싱 (SocketProcessor
) 을 스레드풀에서 실행합니다.SocketChannel
을 HttpServletRequest
, HttpServletResponse
객체로 변환 하여 StandardEngineValve
에 넘겨줍니다.Engine
, Host
, Context
, Wrapper
) 내에서 요청을 처리합니다.DispatcherServlet
에 처리를 위임합니다.org.apache.tomcat.util.net.Acceptor
SynchronizedQueue
) 에 소켓을 래핑하여 등록public class Acceptor<U> implements Runnable {
public void run() {
...
while (!stopCalled) {
...
// 커넥션 생성
socket = endpoint.serverSocketAccept();
...
// 커넥션 프로세싱
if (!endpoint.setSocketOptions(socket)) {
// 프로세싱 실패시, 커넥션 종료
endpoint.closeSocket(socket);
}
}
}
}
public class NioEndpoint extends AbstractJsseEndpoint<NioChannel,SocketChannel> {
protected boolean setSocketOptions(SocketChannel socket) {
...
channel = new NioChannel(bufhandler);
...
// socker 을 socketWrapper 로 변환
NioSocketWrapper newWrapper = new NioSocketWrapper(channel, this);
channel.reset(socket, newWrapper);
connections.put(socket, newWrapper);
socketWrapper = newWrapper;
...
poller.register(socketWrapper); // poller 에 소켓 이벤트 등록
}
}
org.apache.tomcat.util.net.NioEndpoint$Poller
Selector
에 이벤트에 래핑된 소켓을 등록SockerProcessor
) 실행public class Poller implements Runnable {
public void run() {
while (true) {
...
// 앞서 등록된 소켓 이벤트 확인 및 Selector 에 소켓(Channel) 등록
hasEvents = events();
...
// Selector 에서 연산이 필요한 SelectionKey 조회
// SelectionKey 는 Channel 과 Attachment 를 지님
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();
if (socketWrapper != null) {
// 프로세싱
processKey(sk, socketWrapper);
}
}
}
}
public boolean events() {
// 등록된 이벤트 핸들링
for (int i = 0, size = events.size(); i < size && (pe = events.poll()) != null; i++ ) {
NioSocketWrapper socketWrapper = pe.getSocketWrapper();
SocketChannel sc = socketWrapper.getSocket().getIOChannel();
...
// Selector 에 새로 등록이 필요한 이벤트라면
else if (interestOps == OP_REGISTER) {
try {
// Selector 에 읽기 연산이 필요한것으로 등록
sc.register(getSelector(), SelectionKey.OP_READ, socketWrapper);
} catch (Exception x) {
log.error(sm.getString("endpoint.nio.registerFail"), x);
}
}
}
}
protected void processKey(SelectionKey sk, NioSocketWrapper socketWrapper) {
...
// 읽기 연산이 필요한경우
if (sk.isReadable()) {
// 프로세싱
} else if (!processSocket(socketWrapper, SocketEvent.OPEN_READ, true)) {
closeSocket = true;
}
}
}
public boolean processSocket(SocketWrapperBase<S> socketWrapper, SocketEvent event, boolean dispatch) {
...
// SockerProcessor 생성
if (sc == null) {
sc = createSocketProcessor(socketWrapper, event);
} else {
sc.reset(socketWrapper, event);
}
Executor executor = getExecutor();
if (dispatch && executor != null) {
// 스레드풀 내에서 실행
executor.execute(sc);
} else {
sc.run();
}
}
}
org.apache.tomcat.util.net.NioEndpoint$SocketProcessor
Runnable
을 상속하여 스레드풀 내에서 실행됨protected class SocketProcessor extends SocketProcessorBase<NioChannel> {
protected void doRun() {
...
if (socketWrapper.getSocket().isHandshakeComplete()) {
// TLS handshake 가 필요하지 않다면
handshake = 0;
}
...
if (handshake == 0) {
SocketState state = SocketState.OPEN;
if (event == null) {
state = getHandler().process(socketWrapper, SocketEvent.OPEN_READ);
} else {
// 핸들러를 통해 프로세싱
state = getHandler().process(socketWrapper, event);
}
}
}
}
protected static class ConnectionHandler<S> implements AbstractEndpoint.Handler<S> {
public SocketState process(SocketWrapperBase<S> wrapper, SocketEvent status) {
...
// Http11Processor 호출
state = processor.process(wrapper, status);
}
}
public class Http11Processor extends AbstractProcessor {
public SocketState service(SocketWrapperBase<?> socketWrapper) throws IOException {
...
// HTTP 프로토콜 확인 (0.9, 1.0, 1.1)
prepareRequestProtocol();
...
// Request 헤더 파싱
prepareRequest();
...
// KeepAlive 처리
int maxKeepAliveRequests = protocol.getMaxKeepAliveRequests();
if (maxKeepAliveRequests == 1) {
keepAlive = false;
} else if (maxKeepAliveRequests > 0 &&
socketWrapper.decrementKeepAlive() <= 0) {
keepAlive = false;
}
...
// CoyoteAdapter 호출
getAdapter().service(request, response);
}
}
public class CoyoteAdapter implements Adapter {
public void service(org.apache.coyote.Request req, org.apache.coyote.Response res) throws Exception {
...
// StandardEngineValve 호출
connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);
}
}
Valve
를 거쳐 ApplicationFilterChain
에 도달합니다.Valve
만 설정한것으로 보입니다.StandardHostValve
에서 에러페이지를 처리합니다. (Whitelabel Error Page)Serlvet
을 호출public final class ApplicationFilterChain implements FilterChain {
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
...
internalDoFilter(request,response);
}
private void internalDoFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
// 아직 필터링중인 경우
if (pos < n) {
ApplicationFilterConfig filterConfig = filters[pos++];
try {
Filter filter = filterConfig.getFilter();
...
// 다음 필터에서 필터링 수행
filter.doFilter(request, response, this);
}
}
...
// 필터링이 끝났다면 Servlet 호출
servlet.service(request, response);
}
DispatcherServlet
에 전달합니다.