5장_: 임베디드 톰캣으로 웹 서버 띄우기

2026. 2. 5. 14:45·Book/자바 웹 프로그래밍 Next Step

 

오늘은 “톰캣을 설치해서 돌리는 방식” 말고, jar만 가져와서 내 자바 프로젝트에서 main()으로 톰캣을 직접 띄우는 방식을 정리한다.

 

톰캣은 “독립 실행”만 있는 게 아니다

톰캣을 받으면 보통 두 흐름이 있다.

  • 독립 실행 톰캣: 설치(압축 해제) 후 bin/startup 같은 걸로 서버를 직접 띄운다.
  • 임베디드 톰캣: 톰캣이 서버 프로그램이 아니라, 내 앱 안에 라이브러리(jar)로 들어가서 main()에서 실행된다.

오늘 한 방식은 두 번째다.
즉 “톰캣을 따로 켜는 게 아니라”, 자바 프로그램이 톰캣을 생성해서 켜는 구조다.

저 부분을 다운 받은 후 앞축을 해제한다.

 

 

준비: lib/에 톰캣 jar들을 넣고 VS Code에 클래스패스로 올리기

그럼 이렇게 jar파일들이 보인다.

새 프로젝트를 만든 뒤 lib/ 폴더를 만들고, 다운받은 톰캣 관련 jar들을 전부 복사해 넣는다.

VS Code(Java 확장)에서는 settings.json에 아래를 추가한다.

 
{
  "java.project.referencedLibraries": ["lib/**/*.jar"]
}

이 의미는 단순하다.

`lib/` 아래의 모든 `jar`를 프로젝트 클래스패스에 자동으로 추가한다.

그래서 컴파일/실행/자동완성에서 Tomcat 클래스 같은 게 바로 잡힌다.

 

 

main()으로 톰캣 띄우는 런처 코드

package net.slipp;

import java.io.File;
import java.util.logging.Logger;
import org.apache.catalina.startup.Tomcat;

public class WebserverLauncher {
    private static final Logger logger = Logger.getLogger(WebserverLauncher.class.getName());

    public static void main(String[] args) throws Exception {
        String webappDirLocation = "webapp/";
        Tomcat tomcat = new Tomcat();
        tomcat.setPort(8080);
        tomcat.getConnector().setURIEncoding("UTF-8");
        tomcat.getServer().setPort(8005);

        tomcat.addWebapp("", new File(webappDirLocation).getAbsolutePath());
        logger.info("configuring app with basedir: " + new File("./" + webappDirLocation).getAbsolutePath());

        tomcat.start();
        tomcat.getServer().await();
    }
}

여기서 핵심 라인을 하나씩 뜯어보겠다.

 

`Tomcat tomcat = new Tomcat();`

임베디드 톰캣 “엔진 객체”를 만든다.
이 시점엔 아직 서버가 뜬 게 아니다. 그냥 설정할 대상이 생긴 거다.

`tomcat.setPort(8080);`

이건 브라우저가 접속하는 HTTP 포트다.

  • 접속 URL: http://localhost:8080

여기서 8080은 “웹 접속 포트”다.

`tomcat.addWebapp("", webappDirAbsPath);`

이 라인이 “웹 루트”를 지정한다.

  • 첫 번째 인자 ""는 컨텍스트 경로다.
    • ""이면 루트 컨텍스트가 된다 → 즉 /로 붙는다.
  • 두 번째 인자는 실제 정적 파일들이 있는 폴더 경로다.
    • 여기서는 webapp/ 폴더.

즉 이 설정을 하면:

  • http://localhost:8080/ → webapp/ 폴더를 루트로 보는 서버가 된다.

`tomcat.start();`

여기서 톰캣이 실제로 뜬다.
즉, 포트를 열고 서버 스레드들이 준비된다.

`tomcat.getServer().await();`

이게 “프로세스를 살아있게 하는 대기”다.

임베디드 톰캣은 내 프로그램이 주인이다.
내 main()이 끝나면 JVM이 종료되고, JVM이 종료되면 서버도 같이 죽는다.

그래서 await()로 메인 스레드를 붙잡아 두는 것이다.

 

 

그런데 왜 “바로 꺼져서 8080이 안 떴나?

현상은 이런 느낌이다.

  • Run 누름
  • 콘솔 조금 뜨는 듯하다가
  • 프로세스가 종료됨
  • `http://localhost:8080` 접속 안 됨

이건 대부분 이런 구조 때문에 생긴다.

  • main()이 끝나면 JVM이 종료된다
  • JVM이 종료되면 서버도 같이 내려간다
  • 그런데 await()가 어떤 이유로 제대로 대기 상태로 들어가지 못하고 리턴해버리면
    → main()이 끝난다 → JVM 종료 → 서버 종료

즉, 문제는 톰캣이 아예 안 켜진 게 아니라
켜졌다가 main()이 끝나서 같이 죽은 케이스가 많다.

 

 

tomcat.getServer().setPort(8005); 이건 뭐고 왜 필요한가

웹 접속 포트는 8080 그대로다.

  • tomcat.setPort(8080); → HTTP 접속 포트
  • tomcat.getServer().setPort(8005); → Tomcat 서버 내부의 shutdown/await 포트

1) 8005는 브라우저랑 관계가 없다

브라우저로 `http://localhost:8005` 이런 식으로 접속하는 게 아니다.
이 포트는 Tomcat 내부에서 서버를 기다리는(await)/종료 신호 같은 관리용으로 쓰이는 영역이다.

2) 이걸 설정하면 뭐가 좋아지나

핵심 효과는 하나다.

  • tomcat.getServer().await();가 진짜로 블로킹(대기) 해서
  • main()이 끝나지 않고
  • JVM이 살아 있고
  • 따라서 서버가 계속 살아 있다.

즉, “서버가 켜졌다가 바로 꺼지는 문제”를 막는 프로세스 유지용 안전장치다.

 

 

한글 깨짐

setURIEncoding("UTF-8")은 말 그대로 URI 인코딩이다.

즉 이런 상황에서 의미가 있다.

  • GET 쿼리스트링에 한글이 들어갈 때
    예: /?name=홍길동
  • 경로에 한글이 들어갈 때

이때 서버가 URI를 해석할 때 UTF-8로 디코딩하게 만든다.

 

정적 HTML이 깨지는 건 보통 두 가지가 원인이다.

  1. 파일 자체가 UTF-8로 저장되지 않았다
  2. HTML에 charset 선언이 없다(또는 다르다)

그래서 해결은 이쪽이다.

  • 파일을 UTF-8로 저장
  • HTML에 선언 추가
 
<meta charset="UTF-8">

즉,

  • setURIEncoding("UTF-8") = URL/파라미터 쪽
  • meta charset + 파일 저장 인코딩 = HTML 본문 표시 쪽

둘은 대상이 다르다.

 

 

index.html이 “디폴트로 뜨는 이유”

이건 톰캣(그리고 대부분의 웹서버)의 기본 규칙이다.

  • 사용자가 /로 요청하면 디렉토리 루트를 의미한다.
  • 디렉토리 요청에서 파일명을 생략한 경우 서버는 기본 파일을 찾는다.
  • 대표 기본 파일이 index.html이다.

즉,

  • `http://localhost:8080/ `요청
  • `webapp/` 폴더가 루트
  • `webapp/index.html`이 있으면 그걸 자동으로 반환

내가 설정을 한 게 아니라, 서버가 가진 기본 동작이다.

 

 

정적 HTML 수정은 서버 재시작 없이 반영되나?

대부분은 서버 재시작 없이 브라우저 새로고침만 하면 반영된다.

특히 지금 구조가

  • 임베디드 톰캣
  • webapp/를 디렉토리로 붙여서 제공

이런 형태라면, 파일 변경이 바로 반영되는 경우가 많다.

다만 안 바뀌는 것처럼 보이면 대부분 브라우저 캐시다.

  • 강력 새로고침: (mac) Cmd + Shift + R

 

체크 방법: 진짜로 8080이 열렸는지 확인

서버가 살아있는지 확인할 때는 아래가 확실하다.

  • 브라우저 접속: http://localhost:8080
  • 포트 점유 확인(맥):
lsof -nP -iTCP:8080 | head -n 5

여기서 java 프로세스가 잡히면 정상이다.

 

 

 


출처 : 《자바 웹 프로그래밍 Next Step》, 박재성, 로드북

 

'Book > 자바 웹 프로그래밍 Next Step' 카테고리의 다른 글

5장_ : 서블릿 컨테이너가 하는 일: 생명주기와 인스턴스 생성  (0) 2026.02.05
5장_ : Servlet으로 Hello World 출력하기  (0) 2026.02.05
3장_ 로깅: System.out.println() 대신 로깅을 써야 하는 이유  (0) 2026.02.02
3장_ 요구사항 4: 302 status code 적용  (0) 2026.02.01
3장_ 요구사항3: POST방식으로 회원가입  (0) 2026.02.01
'Book/자바 웹 프로그래밍 Next Step' 카테고리의 다른 글
  • 5장_ : 서블릿 컨테이너가 하는 일: 생명주기와 인스턴스 생성
  • 5장_ : Servlet으로 Hello World 출력하기
  • 3장_ 로깅: System.out.println() 대신 로깅을 써야 하는 이유
  • 3장_ 요구사항 4: 302 status code 적용
sqaxe1
sqaxe1
woojoo-devlog 님의 블로그 입니다.
  • sqaxe1
    Woojoo's Devlog
    sqaxe1
  • 전체
    오늘
    어제
    • 분류 전체보기 (148)
      • Backend (9)
        • Servlet (7)
        • Spring (2)
      • Frontend (1)
      • CS (0)
      • Book (33)
        • 자바 웹 프로그래밍 Next Step (30)
        • 테스트 주도 개발: 고품질 쾌속개발을 위한 TDD.. (1)
        • 성공과 실패를 결정하는 1%의 네트워크 원리 (2)
      • Engineering (0)
        • Testing (0)
      • Infra (6)
        • AWS (6)
      • Java (4)
      • Network (1)
      • 김영한 (28)
        • 자바 입문 (8)
        • 실전 자바 - 기본편 (6)
        • 실전 자바 - 중급편 (10)
        • 실전 자바 - 고급편 (4)
      • Web (39)
        • Web Basics (39)
      • Project (24)
        • NeoSquare (0)
        • Memo Evolution (24)
      • 정보처리기사 (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    개발서적
    java
    aws
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
sqaxe1
5장_: 임베디드 톰캣으로 웹 서버 띄우기
상단으로

티스토리툴바