[아이티센 부트캠프] SpringBootApplication 다른 패키지 추가

이언덕·2026년 4월 21일

아이티센 부트캠프

목록 보기
63/115
post-thumbnail

패키지 스캔 범위를 직접 바꿔야 했던 이유

Spring Boot에서는 시작 클래스가 들어 있는 패키지를 기준으로 controller, service, domain 같은 클래스를 찾아서 등록한다.
그래서 처음에는 그냥 파일만 만들면 다 읽히는 것처럼 보이지만, 실제로는 어느 패키지 아래에 두었는지가 아주 중요하다.


이번 상황에서는 src/main/java 아래에 com.example.springedu만 있었던 것이 아니라, thymeleaf.exam이라는 별도 패키지가 하나 더 생겼다.
이때 초보자가 가장 많이 헷갈리는 부분은, 같은 java 폴더 아래에 있으니 당연히 같이 읽힐 것이라고 생각하는 점이다.
하지만 Spring은 폴더 이름만 보고 찾는 것이 아니라, 시작 클래스의 패키지를 기준으로 스캔 범위를 정해서 찾는다.


즉, 이번 수정은 단순히 코드 한 줄을 바꾼 것이 아니라, Spring이 어디까지 찾아가야 하는지를 직접 알려 준 작업이라고 보면 된다.



기본 상태에서는 왜 com.example.springedu 안의 클래스만 잘 읽히는가

처음 프로젝트를 만들면 시작 클래스인 SpringeduApplication이 com.example.springedu 패키지 안에 들어 있다.
이 상태에서는 com.example.springedu와 그 아래 하위 패키지들이 기본 스캔 대상이 된다.


그래서 com.example.springedu.controller, com.example.springedu.domain, com.example.springedu.service처럼 아래쪽에 만든 클래스들은 별도 설정 없이도 잘 읽힌다.
이런 이유로 처음에는 controller를 하나 만들고 실행했을 때 특별한 설정 없이 바로 동작하는 경우가 많다.


여기서 말하는 “읽는다”는 것은 파일을 눈으로 본다는 뜻이 아니다.
Spring이 실행되면서 @Controller, @Service, @Repository, @Component 같은 클래스를 찾아서 자기 관리 대상, 즉 bean으로 등록한다는 뜻이다.
이 과정을 이해해야 왜 어떤 클래스는 인식되고 어떤 클래스는 인식되지 않는지 바로 연결해서 볼 수 있다.



그런데 이번 구조에서는 왜 문제가 생겼는가

이번에는 src/main/java 아래에 기존의 com.example.springedu만 있는 것이 아니라, thymeleaf.exam 패키지가 새로 생겼다.
겉으로 보면 둘 다 같은 java 아래에 있으니 같이 읽혀야 할 것처럼 보인다.


하지만 중요한 기준은 폴더의 물리적인 위치보다 패키지 이름의 시작점이다.
com.example.springedu와 thymeleaf.exam은 서로 같은 트리 아래에 있는 하위 패키지 관계가 아니다.
즉, thymeleaf.exam은 com.example.springedu 밑에 있는 것이 아니라, 아예 다른 시작점에서 출발하는 별도 패키지이다.


그래서 시작 클래스가 com.example.springedu 안에 있는 상태에서는 thymeleaf.exam 쪽 클래스들을 기본 설정만으로는 찾지 못한다.
파일은 분명 존재하는데 Spring이 관리 대상으로 등록하지 않으니, 결과적으로 controller를 못 찾거나 주입이 안 되거나 화면 연결이 안 되는 문제가 생길 수 있다.


즉, 같은 src/main/java 아래에 있다는 것과 Spring이 자동으로 읽는다는 것은 같은 말이 아니다.
초보자는 이 둘을 같은 의미로 받아들이기 쉬운데, 실제로는 전혀 다르다.



그래서 ComponentScan을 왜 추가해야 하는가

이 문제를 해결하려면 Spring에게 직접 스캔 범위를 넓혀서 알려 줘야 한다.
그때 사용하는 것이 @ComponentScan이다.


@ComponentScan은 말 그대로 어떤 패키지들을 스캔할지 직접 지정하는 설정이다.
기본 동작에만 맡기지 않고, “이 패키지도 같이 찾아라”라고 명시하는 역할을 한다.


이번 경우에는 기존 패키지인 com.example.springedu와 새로 추가한 thymeleaf.exam을 함께 적어 주면 된다.
그러면 Spring은 두 패키지를 모두 뒤져서 controller나 domain 같은 관리 대상 클래스를 등록하게 된다.


즉, 이번 수정의 핵심은 이것이다.
기본 스캔 범위에 없는 패키지가 생겼기 때문에, 스캔할 패키지를 직접 추가했다.



수정한 코드는 어떻게 생겼는가

아래처럼 시작 클래스에 @ComponentScan을 추가해서 두 패키지를 함께 지정하면 된다.

// SpringeduApplication.java
package com.example.springedu;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication // `Spring Boot` 시작 설정
@ComponentScan(basePackages = {"com.example.springedu", "thymeleaf.exam"}) // 두 패키지를 함께 스캔
public class SpringeduApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringeduApplication.class, args); // 애플리케이션 실행
	}
}

여기서 가장 중요한 줄은 @ComponentScan(basePackages = {"com.example.springedu", "thymeleaf.exam"})이다.
이 한 줄이 “기존 패키지만 보지 말고 thymeleaf.exam도 같이 찾아라”라는 뜻을 가진다.


만약 이 설정이 없으면 thymeleaf.exam 안에 controller를 잘 만들어 두어도, Spring은 그 존재를 모른 채 실행할 수 있다.
즉, 클래스가 없는 것이 아니라 스캔 범위 밖에 있어서 등록되지 않는 것이다.



코드에서 꼭 이해해야 하는 부분

아래 흐름으로 이해하면 가장 쉽다.

  • @SpringBootApplication이 붙은 시작 클래스가 실행의 기준점이 된다.
  • 기본적으로는 시작 클래스가 있는 패키지와 그 하위 패키지만 자동 스캔한다.
  • thymeleaf.exam은 그 하위 패키지가 아니므로 자동 스캔 대상이 아니다.
  • 그래서 @ComponentScan으로 직접 패키지를 추가해야 한다.

이 흐름을 잡으면 “왜 갑자기 설정을 추가해야 하지?”라는 의문이 거의 사라진다.
문법을 외우는 것이 아니라, Spring이 클래스를 찾는 범위를 넓혀 주는 작업이라고 이해하면 된다.


그리고 여기서 controller와 domain이 읽힌다는 말도 정확히 보면, 단순히 해당 파일을 열 수 있다는 뜻이 아니다.
Spring이 실행 시점에 찾아서 관리하고, 필요하면 연결하고, 요청이 왔을 때 사용할 수 있는 상태로 만든다는 뜻이다.
이 의미를 알고 보면 “읽는다”는 표현이 훨씬 선명해진다.



src main java 아래에 있으면 다 되는 것 아닌가

이 부분이 가장 많이 헷갈린다.
결론부터 말하면, 아니다.
src/main/java 아래에 있다는 사실만으로 자동 스캔이 보장되지는 않는다.


src/main/java는 자바 소스 파일을 두는 기본 위치일 뿐이다.
그 아래에서 실제로 어떤 패키지 구조를 가지는지는 별개 문제다.
Spring은 실행할 때 시작 클래스의 패키지를 기준으로 스캔하기 때문에, 같은 java 아래에 있더라도 패키지 시작점이 다르면 자동으로 포함되지 않을 수 있다.


예를 들어 com.example.springedu.controller는 com.example.springedu의 아래쪽이라서 기본 스캔 대상이 된다.
하지만 thymeleaf.exam은 아예 다른 이름으로 시작하므로 기본 대상이 아니다.
이 차이를 분명히 알아야 다음에 패키지 구조를 바꿀 때도 헤매지 않는다.


즉, 중요한 기준은 src/main/java 아래에 있느냐가 아니라, 시작 클래스 기준 스캔 범위 안에 있느냐이다.



여기서 같이 기억하면 좋은 점

이번 문제는 단순히 Thymeleaf를 쓰기 위해 설정 하나 추가한 정도로 끝나지 않는다.
프로젝트 구조를 바꾸거나 패키지를 나눌 때마다 다시 만날 수 있는 기본 원리이다.


처음에는 “왜 분명 클래스가 있는데 인식이 안 되지?”라고 느껴질 수 있다.
그럴 때는 코드 자체를 의심하기 전에, 먼저 시작 클래스 위치와 스캔 범위를 확인하는 습관을 들이면 좋다.


특히 패키지를 새로 만들었는데 controller가 동작하지 않거나 bean을 찾지 못한다는 오류가 나오면, 가장 먼저 스캔 범위를 의심해 보면 된다.
이 흐름을 알고 있으면 디렉터리 구조를 바꾸는 작업이 훨씬 덜 막막해진다.



정리

이번 수정은 thymeleaf.exam 패키지가 com.example.springedu의 하위 패키지가 아니기 때문에 필요했다.
기본 설정만으로는 Spring이 그 패키지까지 자동으로 스캔하지 못하므로, @ComponentScan으로 직접 범위를 추가해 준 것이다.


결국 핵심은 하나다.
Spring은 시작 클래스 기준으로 패키지를 스캔하므로, 구조가 바뀌면 스캔 범위도 함께 확인해야 한다.
이 점만 확실히 잡고 있으면, 앞으로 패키지를 나눌 때 왜 어떤 클래스는 읽히고 어떤 클래스는 안 읽히는지 스스로 판단할 수 있다.

0개의 댓글