Tomcat
글
-
Tomcat 소스 파헤치기 1: AI와 함께 소스를 읽는 방법과 분석 지도
Tomcat이 무엇이고 어떻게 동작하며 어디에 쓰는지를 그림과 3분 실습으로 먼저 보고 시작하는, Tomcat 소스 읽기 연재의 첫 글입니다. 어떤 판(main 브랜치, 12.0.0-M1)을 읽는지와 안정판 11.0.x와의 차이, 서블릿 스펙 버전, 같은 소스를 받아 도커에서 Ant로 빌드하는 법, 74만 줄짜리 소스의 폴더 지도, 요청 하나가 Acceptor에서 서블릿까지 지나는 큰 길, 그리고 AI가 쓴 노트를 소스로 다시 확인하며 읽는 방법을 정리합니다.
-
Tomcat 소스 파헤치기 2: 전체 지도 — Server, Service, Connector, 그리고 컨테이너 넷
Tomcat 소스를 처음 여는 사람을 위한 지도입니다. server.xml의 Server·Service·Connector·Engine·Host가 각각 어떤 클래스가 되는지, Engine·Host·Context·Wrapper 네 컨테이너가 부모·자식으로 어떻게 이어지는지, 커넥터(Coyote)와 서블릿 컨테이너(Catalina)를 왜 나눴고 Adapter 하나로 어떻게 잇는지, Jasper·EL·JULI·Naming은 어디에 있는지를 실제 소스와 직접 돌린 예제로 확인합니다.
-
Tomcat 소스 파헤치기 3: Lifecycle과 기동 — catalina.sh start 뒤에 일어나는 일
catalina.sh start 한 줄 뒤에서 Bootstrap이 클래스로더를 만들고, Catalina가 Digester로 server.xml을 객체 나무로 바꾸고, 모든 부품이 같은 Lifecycle 상태 기계를 따라 init·start되는 과정을 소스로 따라갑니다. 부모가 자식을 어떤 순서로 시작시키는지, 커넥터가 실패해도 서버가 뜨는 이유, 종료 포트 8005가 하는 일을 리스너와 예제로 직접 확인합니다.
-
Tomcat 소스 파헤치기 4: 클래스로더 — 웹앱마다 따로 보는 클래스
Tomcat 한 프로세스 안에서 두 웹앱이 같은 이름의 서로 다른 클래스를 쓸 수 있는 이유를 소스에서 찾습니다. Bootstrap 이 만드는 common·server·shared 로더와 catalina.properties, 웹앱마다 하나씩 생기는 WebappClassLoaderBase 가 부모 위임 순서를 뒤집는 loadClass(), jakarta.servlet 같은 예외를 고르는 filter(), delegate 설정, reloadable 리로드와 스레드 누수 경고까지 기준 커밋을 빌드한 Tomcat 으로 직접 확인합니다.
-
Tomcat 소스 파헤치기 5: 커넥터와 NIO 엔드포인트 — 연결은 어떤 스레드가 받나
server.xml 의 <Connector port="8080"> 한 줄이 Connector, Http11NioProtocol, NioEndpoint 라는 세 객체가 되고, 그 안에서 Acceptor·Poller·작업 스레드가 연결 하나를 나눠 맡는 과정을 소스로 따라갑니다. keep-alive 연결이 요청 사이에 스레드를 놓아주는 길, JDK 와 다르게 동작하는 Tomcat 의 스레드 풀(TaskQueue), maxConnections·acceptCount·maxThreads 가 걸리는 자리를 jstack 과 소켓 예제로 확인하고, main 브랜치에서 NIO2 커넥터가 빠진 것도 11.0.x 와 비교합니다.
-
Tomcat 소스 파헤치기 6: HTTP/1.1 요청 읽기 — 바이트가 coyote Request가 되기까지
소켓에서 읽은 바이트가 Http11Processor의 service() 루프 안에서 요청 줄과 헤더로 나뉘어 coyote Request가 되는 과정을 소스로 따라갑니다. 문자열을 늦게 만드는 MessageBytes, maxHttpHeaderSize와 maxHeaderCount 한도, 잘못된 요청이 HTML 400 페이지가 되는 길, keep-alive와 chunked 응답이 정해지는 자리를 날 요청을 보내 직접 확인합니다.
-
Tomcat 소스 파헤치기 7: CoyoteAdapter와 Mapper — 요청은 어느 서블릿으로 가나
다 읽은 HTTP 요청이 Coyote에서 Catalina로 넘어가는 다리인 CoyoteAdapter, 그 안에서 URI를 디코딩하고 정규화하는 postParseRequest(), Host·Context·Wrapper를 고르는 Mapper의 규칙 순서를 소스로 따라갑니다. 서블릿 여섯 개로 매핑 우선순위를, curl로 %2F·..·;jsessionid가 어떻게 처리되는지를, 붙잡아 둔 요청 객체로 RequestFacade가 왜 있는지를 직접 확인합니다.
-
Tomcat 소스 파헤치기 8: 파이프라인과 밸브 — 컨테이너마다 걸린 처리 사슬
server.xml의 <Valve> 한 줄은 소스에서 무엇이 될까요. Engine·Host·Context·Wrapper가 저마다 가진 파이프라인, 그 끝에서 다음 컨테이너를 고르는 기본 밸브 넷, 다음 밸브를 부르지 않아 요청을 끊는 법, 오류 페이지를 그리는 ErrorReportValve, 응답이 끝난 뒤에야 쓰이는 접근 로그와 RemoteIpValve의 함정까지, 직접 쓴 밸브를 세 컨테이너에 걸어 소스와 함께 확인합니다.
-
Tomcat 소스 파헤치기 9: 필터 체인과 서블릿 호출 — service()가 불리기까지
밸브 사슬의 맨 끝에서 Tomcat이 서블릿 인스턴스를 꺼내고, 이 요청에 맞는 필터를 골라 배열로 묶고, 그 배열을 한 칸씩 넘기며 마지막에 service()를 부르는 과정을 소스로 따라갑니다. 서블릿 init()이 불리는 시점, 필터 순서가 정해지는 규칙, forward와 include의 차이, 예외가 오류 페이지로 바뀌는 길도 예제로 확인합니다.
-
Tomcat 소스 파헤치기 10: 웹앱 배포와 Context 설정 — WAR 하나가 서비스되기까지
webapps 폴더에 WAR 파일 하나를 넣으면 Tomcat 안에서 무슨 일이 일어나는지 소스로 따라갑니다. HostConfig가 10초마다 폴더를 살펴 Context를 만들고, ContextConfig가 web.xml·conf/web.xml·어노테이션을 합치고 ServletContainerInitializer를 찾으며, StandardContext.startInternal()이 SCI·리스너·필터·서블릿을 정해진 순서로 깨웁니다. Spring의 SpringServletContainerInitializer가 불리는 자리도 Tomcat 쪽에서 확인합니다.
-
Tomcat 소스 파헤치기 11: 세션 — JSESSIONID는 어떻게 만들고 지우나
request.getSession() 한 줄 뒤에서 Tomcat이 세션 ID를 어디서 읽고, 어떻게 만들고, 언제 지우는지 소스로 따라갑니다. 쿠키와 ;jsessionid, SecureRandom으로 만드는 32글자 ID, 요청 때와 뒷정리 스레드에서 일어나는 두 가지 만료, 재시작 때 세션을 파일에 저장하는 StandardManager까지 예제 셋으로 직접 확인합니다.
-
Tomcat 소스 파헤치기 12: 비동기 서블릿과 논블로킹 I/O — 스레드를 놓아주는 법
startAsync()를 부른 서블릿은 응답을 끝내지 않고 돌아가고, 요청 처리 스레드는 풀로 돌아갑니다. 그 사이 요청을 붙들고 있는 AsyncStateMachine의 상태 전이, complete()와 dispatch()가 컨테이너 스레드로 돌아오는 길, 1초마다 도는 타임아웃 검사, ReadListener가 Poller와 함께 동작하는 방식을 Tomcat 소스와 스레드 이름을 찍는 예제로 따라갑니다.
-
Tomcat 소스 파헤치기 13: Jasper — JSP가 서블릿이 되기까지
hello.jsp를 처음 요청하면 Tomcat 안에서 무슨 일이 일어날까요? JspServlet이 요청을 받아 JSP 파일을 노드 트리로 읽고, 자바 소스로 옮겨 쓰고, ecj로 컴파일해 work 폴더에 .class를 남긴 뒤 그 클래스를 서블릿처럼 부르는 과정을 Jasper 소스로 따라갑니다. 생성된 .java 파일을 직접 열어 보고, JSP를 고쳤을 때 언제 다시 컴파일되는지(development, modificationTestInterval, checkInterval)도 예제로 확인합니다.
-
Tomcat 소스 파헤치기 14: 인증과 Realm — security-constraint는 어떻게 지켜지나
web.xml 의 security-constraint 와 login-config, server.xml 의 Realm, tomcat-users.xml 이 소스에서 어떻게 이어지는지 따라갑니다. 웹앱이 시작될 때 Authenticator 밸브가 끼워지는 자리, AuthenticatorBase.invoke() 의 검사 순서, URL 에 걸린 제약을 고르는 네 번의 검색, BASIC 과 FORM 의 차이, Realm 과 CredentialHandler 의 역할을 실제 소스와 401·403·303 응답으로 확인합니다.
-
Tomcat 소스 파헤치기 15: HTTP/2와 WebSocket — 업그레이드로 갈아타는 프로토콜
HTTP/1.1로 시작한 연결이 어떻게 HTTP/2나 WebSocket으로 바뀌는지 Tomcat 소스로 따라갑니다. UpgradeProtocol과 UpgradeToken, Http11Processor의 업그레이드 처리, 연결 하나에 스트림 여럿을 싣는 Http2UpgradeHandler, 필터 하나로 들어오는 WebSocket의 WsFilter와 WsHttpUpgradeHandler를 h2c 요청과 JDK WebSocket 클라이언트로 직접 확인합니다.
-
Tomcat 소스 파헤치기 16: 내장 Tomcat, JMX, 로깅 — 그리고 연재를 마치며
server.xml 없이 Tomcat을 코드로 띄우는 startup/Tomcat 클래스가 무엇을 대신 만들어 주고 무엇을 만들어 주지 않는지, 부품마다 MBean이 올라가는 JMX 등록 과정, 웹앱마다 로그 설정을 따로 두는 JULI의 ClassLoaderLogManager를 소스와 예제로 확인하고, 16편 연재를 정리합니다.