Spring Boot 프로젝트 구조 이해하기
springbluemiv

Spring Boot 프로젝트 구조 이해하기

Spring Boot 프로젝트의 폴더 구조와 주요 파일들의 역할을 이해합니다.

4 min read
AD

1. Spring Boot 프로젝트 구조

Spring Initializr로 프로젝트를 생성하면 기본적으로 아래와 같은 구조가 만들어집니다. 개발 환경 설정과 프로젝트 생성 흐름은 Spring Boot 개발 환경 설정을 먼저 보면 이해하기 쉽습니다.

demo/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/example/demo/
│   │   │       └── DemoApplication.java
│   │   └── resources/
│   │       ├── application.properties
│   │       ├── static/
│   │       └── templates/
│   └── test/
│       └── java/
│           └── com/example/demo/
│               └── DemoApplicationTests.java
├── build.gradle
└── settings.gradle

처음 보면 폴더가 많아 보이지만, 크게 보면 다음과 같이 나눌 수 있습니다.

  • src/main/java: 실제 애플리케이션 코드
  • src/main/resources: 설정 파일과 정적 리소스
  • src/test/java: 테스트 코드
  • build.gradle: 프로젝트 빌드 및 의존성 설정

2. src/main/java

src/main/java는 Java 소스 코드를 작성하는 위치입니다. Spring Boot 애플리케이션의 컨트롤러, 서비스, 레포지토리, 도메인 클래스 등이 이 폴더 아래에 위치합니다.

예를 들어 기본 패키지 이름을 com.example.demo로 만들었다면, 다음 경로에 코드가 생성됩니다.

src/main/java/com/example/demo/

Spring Boot에서는 보통 메인 클래스가 있는 패키지를 기준으로 하위 패키지의 컴포넌트를 자동으로 탐색합니다. 그래서 특별한 이유가 없다면 DemoApplication.java와 같은 메인 클래스 아래에 기능별 패키지를 만드는 것이 좋습니다.

com/example/demo/
├── DemoApplication.java
├── controller/
├── service/
├── repository/
├── domain/
└── dto/

각 패키지의 역할은 다음과 같습니다.

패키지역할
controllerHTTP 요청을 받고 응답을 반환
service비즈니스 로직 처리
repository데이터베이스 접근
domain핵심 도메인 객체 또는 Entity
dto요청/응답 데이터를 전달하는 객체

3. DemoApplication.java

Spring Boot 프로젝트를 생성하면 DemoApplication.java 파일이 만들어집니다. 이 파일은 애플리케이션의 시작점입니다.

package com.example.demo;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
 
@SpringBootApplication
public class DemoApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
 
}

main 메서드에서 SpringApplication.run()을 호출하면 Spring Boot 애플리케이션이 실행됩니다.

여기서 중요한 것은 @SpringBootApplication 어노테이션입니다. 이 어노테이션은 아래 기능들을 합쳐놓은 어노테이션입니다.

  • @SpringBootConfiguration: Spring Boot 설정 클래스임을 나타냄
  • @EnableAutoConfiguration: Spring Boot의 자동 설정 기능 활성화
  • @ComponentScan: 현재 패키지와 하위 패키지에서 컴포넌트 탐색

즉, DemoApplication.java가 있는 패키지를 기준으로 Spring Bean을 찾기 때문에, 일반적으로 이 클래스는 프로젝트의 최상위 패키지에 두는 것이 좋습니다. Spring이 객체를 생성하고 연결하는 원리는 IoC와 DI 이해하기를 함께 보면 자연스럽게 이어집니다.

4. src/main/resources

src/main/resources는 Java 코드가 아닌 설정 파일과 리소스를 관리하는 위치입니다.

src/main/resources/
├── application.properties
├── static/
└── templates/

4.1. application.properties

application.properties는 Spring Boot 애플리케이션의 설정을 작성하는 파일입니다. 설정 파일의 문법과 환경별 분리는 application.yml과 application.properties 설정에서 더 자세히 다룹니다.

server.port=8080
spring.application.name=demo

위 설정은 서버 포트를 8080으로 지정하고, 애플리케이션 이름을 demo로 설정합니다.

설정이 많아지면 application.yml 파일을 사용할 수도 있습니다.

spring.datasource.url=jdbc:mysql://localhost:3306/demo
spring.datasource.username=root
spring.datasource.password=password

같은 설정을 application.yml로 작성하면 계층 구조로 표현할 수 있습니다.

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/demo
    username: root
    password: password

propertiesyml 중 하나만 사용해도 됩니다. 실무에서는 설정이 많아질수록 가독성이 좋은 yml을 많이 사용합니다.

4.2. static

static 폴더는 정적 파일을 넣는 위치입니다. 이미지, CSS, JavaScript 파일 등을 둘 수 있습니다.

src/main/resources/static/
├── images/
│   └── logo.png
├── css/
│   └── style.css
└── js/
    └── app.js

예를 들어 static/images/logo.png 파일을 넣으면 브라우저에서 아래 주소로 접근할 수 있습니다.

http://localhost:8080/images/logo.png

4.3. templates

templates 폴더는 서버 사이드 템플릿 파일을 넣는 위치입니다. Thymeleaf 같은 템플릿 엔진을 사용할 때 HTML 파일을 이곳에 둡니다.

src/main/resources/templates/
└── index.html

다만 REST API 서버만 만든다면 templates 폴더를 사용하지 않는 경우도 많습니다.

5. src/test/java

src/test/java는 테스트 코드를 작성하는 위치입니다.

src/test/java/com/example/demo/
└── DemoApplicationTests.java

Spring Initializr로 프로젝트를 만들면 기본 테스트 클래스가 생성됩니다.

package com.example.demo;
 
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
 
@SpringBootTest
class DemoApplicationTests {
 
    @Test
    void contextLoads() {
    }
 
}

@SpringBootTest는 Spring Boot 애플리케이션 컨텍스트가 정상적으로 로딩되는지 확인할 때 사용할 수 있습니다. 처음에는 비어 있는 테스트처럼 보이지만, 애플리케이션 설정에 문제가 있으면 이 테스트가 실패합니다.

6. build.gradle

build.gradle은 Gradle 빌드 설정 파일입니다. 프로젝트에서 사용할 플러그인, Java 버전, 의존성 등을 정의합니다.

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.3.0'
    id 'io.spring.dependency-management' version '1.1.5'
}
 
group = 'com.example'
version = '0.0.1-SNAPSHOT'
 
java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}
 
repositories {
    mavenCentral()
}
 
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
 
tasks.named('test') {
    useJUnitPlatform()
}

주요 항목은 다음과 같습니다.

  • plugins: Java, Spring Boot 관련 플러그인 설정
  • repositories: 의존성을 다운로드할 저장소 설정
  • dependencies: 프로젝트에서 사용할 라이브러리 설정
  • tasks.named('test'): JUnit 5를 사용하도록 테스트 설정

새로운 라이브러리가 필요하면 보통 dependencies 블록에 추가합니다.

7. settings.gradle

settings.gradle은 Gradle 프로젝트의 이름과 멀티 모듈 설정을 관리하는 파일입니다.

pluginManagement {
    repositories {
        maven { url = 'https://repo.spring.io/milestone' }
        gradlePluginPortal()
    }
}
 
rootProject.name = 'demo'

단일 프로젝트에서는 대부분 rootProject.name 정도만 확인하면 됩니다. 멀티 모듈 프로젝트를 구성할 때는 이 파일에 하위 모듈을 추가합니다.

rootProject.name = 'demo'
 
include 'api'
include 'common'

처음 Spring Boot를 공부할 때는 settings.gradle보다 build.gradle을 더 자주 수정하게 됩니다.

8. 실무에서 자주 사용하는 패키지 구조

작은 예제에서는 메인 클래스와 컨트롤러를 같은 패키지에 두어도 문제가 없습니다. 하지만 프로젝트가 커지면 역할별로 패키지를 나누는 것이 좋습니다.

com/example/demo/
├── DemoApplication.java
├── controller/
│   └── UserController.java
├── service/
│   └── UserService.java
├── repository/
│   └── UserRepository.java
├── domain/
│   └── User.java
└── dto/
    ├── UserCreateRequest.java
    └── UserResponse.java

예를 들어 사용자 목록을 조회하는 API를 만든다면 흐름은 다음과 같습니다.

UserController

UserService

UserRepository

Database

각 계층의 책임을 나누면 코드가 많아져도 유지보수하기 쉬워집니다.

  • Controller: 요청과 응답 처리에 집중
  • Service: 핵심 로직 처리에 집중
  • Repository: 데이터 조회와 저장에 집중
  • Domain: 비즈니스의 핵심 개념 표현
  • DTO: 외부로 주고받는 데이터 표현

8.1. 실무에서 패키지를 나눌 때의 기준

처음부터 패키지를 너무 세밀하게 나누면 오히려 이동 비용이 커집니다. 작은 프로젝트에서는 controller, service, repository, domain, dto 정도로 시작하고, 기능이 커질 때 user, order, payment처럼 도메인 기준으로 한 번 더 나누는 편이 관리하기 쉽습니다.

com/example/demo/
├── user/
│   ├── controller/
│   ├── service/
│   ├── repository/
│   ├── domain/
│   └── dto/
└── order/
    ├── controller/
    ├── service/
    ├── repository/
    ├── domain/
    └── dto/

제가 프로젝트를 시작할 때는 먼저 역할 기준으로 단순하게 나누고, 특정 도메인의 파일이 많아지기 시작하면 도메인 기준 구조로 옮기는 편입니다. 중요한 것은 처음부터 완벽한 구조를 만드는 것이 아니라, 팀이 파일 위치를 예측할 수 있게 일관성을 유지하는 것입니다.

9. 참고 자료

10. 정리

Spring Boot 프로젝트 구조는 처음에는 복잡해 보이지만, 역할을 기준으로 보면 어렵지 않습니다.

  • src/main/java에는 실제 애플리케이션 코드를 작성합니다.
  • DemoApplication.java는 애플리케이션의 시작점입니다.
  • src/main/resources에는 설정 파일과 정적 리소스를 둡니다.
  • src/test/java에는 테스트 코드를 작성합니다.
  • build.gradle에는 플러그인, Java 버전, 의존성을 설정합니다.
  • 프로젝트가 커지면 controller, service, repository, domain, dto처럼 역할별로 패키지를 나누는 것이 좋습니다.

프로젝트 구조를 이해하면 이후에 Controller, Service, Repository, JPA, 테스트를 학습할 때 각각의 코드가 어디에 위치해야 하는지 자연스럽게 이해할 수 있습니다.

AD

관련 글

새 글을 놓치지 마세요

RSS 피드를 구독하면 새로운 글이 올라올 때마다 받아볼 수 있습니다.

RSS 구독하기