Spring Boot를 사용하다 보면 ApplicationContextException: Unable to start web server라는 오류 메시지를 만나는 경우가 많다. 이 오류는 주로 Spring Boot 애플리케이션이 웹 서버를 시작하지 못해 발생하며, 그 이유는 매우 다양하다. 특히, 추가적인 Spring 설정을 넣거나, 잘못된 설정이 적용되었을 때 나타난다.
Spring Boot는 Tomcat, Jetty, Undertow 같은 내장 웹 서버를 자동으로 실행하는데, 이 과정에서 문제가 생기면 애플리케이션이 아예 시작하지 못하고 종료된다. 이번 글에서는 이 문제의 주요 원인과 해결 방안을 심층적으로 다루며, 실무에서 부딪히는 문제들을 빠르게 해결할 수 있도록 돕는다.
주요 오류 메시지의 구조 이해하기
ApplicationContextException의 핵심 내용
- 원인: Spring 애플리케이션 컨텍스트가 정상적으로 초기화되지 않음
- 결과: 내장 웹 서버가 정상 구동되지 않음
- 메시지: ApplicationContextException: Unable to start web server
이 오류는 보통 그 아래에 Caused by 블록이 따라오며, 진짜 문제의 단서를 제공한다. 예를 들어, Tomcat 포트 충돌, Bean 초기화 실패, 잘못된 의존성 주입 등이 있을 수 있다.
포트 충돌 문제
포트가 이미 사용 중일 때 발생하는 문제
가장 흔한 이유 중 하나는 이미 해당 포트를 다른 애플리케이션이 사용 중이라는 점이다. Spring Boot의 기본 포트는 8080이다. 예를 들어, 같은 PC에서 또 다른 Spring Boot 애플리케이션을 실행하거나, Docker 컨테이너가 8080을 점유하고 있으면 이 문제가 발생한다.
해결 방법
- application.properties 또는 application.yml에서 다른 포트로 변경:
- server.port=8081
- 실행 시 명령줄에서 포트 지정:
- java -jar app.jar --server.port=8081
Bean 초기화 실패 문제
@Bean, @Component, @Service 등록 문제
Spring은 컨텍스트를 시작할 때 모든 Bean을 초기화한다. 이때 Bean 생성 과정에서 NullPointerException, IllegalArgumentException 같은 런타임 예외가 발생하면 ApplicationContextException이 터진다.
해결 방법
- @Component, @Service, @Repository, @Controller로 등록된 클래스에서 의존성을 주입하는 필드가 잘 주입되었는지 확인.
- @Autowired 대상이 null인지, @Qualifier 이름이 잘 맞는지 점검.
- @Configuration 클래스 내의 @Bean 메서드에서 null이나 잘못된 값이 반환되지 않는지 확인.
의존성 충돌 문제
Spring Boot 버전과 라이브러리 호환성
Spring Boot는 BOM(Bill of Materials) 방식으로 의존성을 관리한다. 그런데 명시적으로 특정 라이브러리 버전을 선언하거나, 호환되지 않는 의존성을 넣으면 충돌이 발생해 ApplicationContext가 깨진다.
해결 방법
- pom.xml (Maven) 또는 build.gradle (Gradle)에서 불필요한 버전 명시를 제거.
- Spring Boot Starter 패키지를 중심으로 의존성을 정리.
- mvn dependency:tree 또는 ./gradlew dependencies로 의존성 트리를 분석해 중복 또는 충돌 확인.
WebEnvironment 설정 문제
추가 설정으로 인한 Embedded Web Server 비활성화
질문 링크의 문제처럼 @SpringBootTest(webEnvironment = WebEnvironment.NONE) 같은 설정이나, @EnableAutoConfiguration(exclude = ...)로 웹 서버 관련 자동 구성을 꺼버리면, 실제로는 웹 서버를 실행할 수 없게 된다.
해결 방법
- 테스트 클래스에서 필요한 WebEnvironment 옵션을 적절히 설정:
- @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
- application.properties에서 웹 서버 비활성화 옵션이 있는지 확인.
Tomcat 종속성 문제
내장 Tomcat 누락
Spring Boot에서 기본적으로 사용하는 내장 Tomcat이 누락되거나 제외되면, 웹 서버가 구동되지 않는다.
해결 방법
- pom.xml에 spring-boot-starter-web 의존성이 포함되어 있는지 확인.
- Gradle 사용 시 implementation 'org.springframework.boot:spring-boot-starter-web' 추가.
- war로 배포할 경우, 내장 Tomcat 대신 외부 Tomcat 사용 여부 확인.
잘못된 프로파일 적용 문제
실행 환경에 맞지 않는 Profile
Spring Boot는 @Profile 어노테이션이나 application-{profile}.properties로 환경별 설정을 구분한다. 잘못된 profile이 적용되면 필요한 Bean이 아예 로딩되지 않아 서버 시작에 실패할 수 있다.
해결 방법
- 활성화된 profile을 명확히 지정:
- java -jar app.jar --spring.profiles.active=prod
- application.properties 내에서 spring.profiles.active 설정.
로그로 문제 분석하기
로그에서 Caused by 찾기
ApplicationContextException만 보고는 해결할 수 없다. 반드시 로그에서 Caused by 블록을 찾아 어떤 예외가 발생했는지 분석해야 한다.
분석 포인트
- Bean 이름과 클래스: 어떤 Bean에서 문제가 발생했는지
- 구체적 예외 클래스: NullPointerException, IllegalStateException 등
- 스택 트레이스: 어느 줄에서 예외가 발생했는지
실전 예제: 문제 해결 플로우
- 애플리케이션 실행 → 실패
- 콘솔 로그 확인 → ApplicationContextException 발생
- 로그 스크롤 → Caused by 항목 찾기
- 어떤 설정, Bean, 의존성에서 문제 발생했는지 파악
- 문제 수정 → 다시 실행
실전 팁: 개발 환경 점검
- IDE에서 Run Configurations 확인.
- 로컬 포트 점유 여부 netstat -an | grep 8080으로 확인.
- application.properties 파일의 잘못된 설정 탐지.
- Gradle/Maven 빌드 시 Warning 무시하지 않기.
Spring Boot ApplicationContextException 방지하는 모범 사례
* 최소한의 의존성으로 프로젝트 시작
- 필요 없는 라이브러리 추가하지 않기.
- Starter 패키지를 중심으로만 구성.
* Bean 생성 순서와 주입 관계 명확히 하기
- 생성자 주입을 우선 사용.
- 순환 의존성 피하기.
* 환경별 설정 명확히 분리
- 개발(dev), 운영(prod), 테스트(test) 별 properties 분리.
- profile별 Bean 및 설정 충돌 방지.
결론
Spring Boot에서 ApplicationContextException: Unable to start web server는 단순한 포트 문제부터, 깊은 Bean 충돌, 의존성 문제까지 다양한 원인으로 발생할 수 있다. 로그 분석, 설정 점검, 의존성 정리라는 세 가지 키워드를 중심으로 접근하면 문제 해결 속도를 높일 수 있다. 특히 StackOverflow 질문처럼 추가 설정을 넣은 뒤 발생한 문제라면, 꼭 web 관련 설정이 비활성화되거나, 의존성에서 충돌이 발생하지 않았는지 꼼꼼히 살펴보길 권한다.
'delphi' 카테고리의 다른 글
Jetpack Compose HorizontalPager에서 NavController로 화면 이동하는 방법 (0) | 2025.06.20 |
---|---|
AWS S3에서 대용량 CSV 파일을 효율적으로 스트리밍하고 라인별로 처리하는 방법 (0) | 2025.06.20 |
PHP GoCardless Pro Uncaught Error Class GoCardlessPro\Client Not Found 해결 가이드 (0) | 2025.06.19 |
TListView에서 TListItem의 위치를 변경하는 방법 (0) | 2024.08.16 |
대용량 UTF8 파일 처리 방법(효율적인 접근과 변환 방법) (0) | 2024.08.14 |