[강의] Spring Boot 코드 아키텍처

Jerry·2025년 8월 4일

Spring Boot 프로젝트 구조

Spring Boot 프로젝트의 기본 구조

  • 빌드 및 설정: build.gradle, settings.gradle, Gradle Wrapper 파일로 프로젝트 빌드와 실행 환경을 정의한다
  • 소스 코드: src/main/java에 메인 클래스와 controller, service, repository, domain 패키지로 계층형 구조를 구성한다
  • 리소스 및 테스트: src/main/resources에 설정 파일, 정적 리소스, 뷰 템플릿을 두고 src/test/java에 단위/통합 테스트 코드 담당

Java 애플리케이션 메인 클래스의 위치

애플리케이션 메인 클래스란 Spring Boot 애플리케이션의 진입점을 정의한 메인 클래스이다.
@SpringBootApplication으로 자동 설정과 컴포넌트 스캔을 활성화하고, SpringApplication.run()으로
스프링 컨텍스트와 내장 서버를 구동한다. (web이 있을 경우)
→ Spring에서는 존재하지 않았던 main을 Spring Boot에서는 드디어 확인 할 수 있게 되었다.

프로젝트 - Resources

Resources는 애플리케이션의 환경 설정, 정적 파일, 템플릿 등 비자바 리소스를 관리하는 디렉토리이다.
빌드 시 이 파일들은 클래스패스(classpath:/)에 포함되어 애플리케이션 실행 시 자동으로 로드 된다.

  • application.yml : 스프링 환경 설정 파일
  • static/ : 정적 파일 (CSS, JS, 이미지, HTML 등)
  • templates/ : 동적 뷰 템플릿 (Thymeleaf, Mustache 등)
  • public/ : 추가 정적 리소스 제공 디렉토리

test 경로

test영역은 애플리케이션의 단위 및 통합 테스트 코드를 작성하는 전용 디렉토리이다.
메인 코드(src/main/java)와 동일한 패키지 구조를 유지해 테스트 대상을 쉽게 매핑할 수 있다.
JUnit, Spring Test 등의 도구를 활용해 기능 검증 및 회귀 테스트를 수행하는 공간으로 사용된다.

Gradle 빌드

빌드 환경- Gradle

Gradle은 JVM 기반의 오픈소스 빌드 자동화 도구로, Groovy·Kotlin DSL을 사용해 유연하게 프로젝트
빌드 과정을 정의할 수 있다. 의존성 관리(Maven Central 등)와 멀티 프로젝트 빌드를 손쉽게 지원하며,
증분 빌드와 캐싱으로 빌드 속도를 최적화한다.
Java뿐 아니라 Kotlin, Android, Spring 등 다양한 생태계에서 표준 빌드 도구로 널리 활용된다.
→ Google이 2013년 Android Studio를 발표하면서 Gradle을 기본 빌드 도구로 채택 된 이후 활성화됨

Gradle 빌드 시스템

아래 경로는 Gradle 프로젝트 생성시 생성되는 기초 파일 리스트로 해당 파일을 통해 Gradle 기능을
활용할 수 있다.

  • build.gradle: 프로젝트의 핵심 빌드 정의, 의존성 추가 시 반드시 수정해야하는 파일
  • gradle-wrapper.properties: 팀 간 동일 Gradle 환경을 보장하는 핵심 설정

build.gradle 파일 구성 실습

build.gradle은 Gradle 빌드 도구의 설정 파일로, 프로젝트의 플러그인, 의존성, 빌드 작업을 정의한다.
기본적으로 Groovy DSL로 작성되며, 조건문과 함수 작성이 가능한 스크립트 형태로 동작한다.
이를 통해 빌드·배포·테스트 과정을 자동화하고 관리할 수 있다.

  • plugins: 프로젝트에서 사용할 Gradle 플러그인 선언 (Spring Boot, Java 등)
  • repositories: 의존성을 다운로드할 저장소 (예: Maven Central)
  • dependencies: 애플리케이션과 테스트에서 사용할 의존성 라이브러리 목록
  • tasks: 커스텀 빌드 작업 정의 (예: 배포용 Jar 빌드)

플러그인 설정

  • Gradle은 기본적으로 Java 프로젝트인지, Spring 프로젝트인지를 알지 못한다.
  • 그래서 필요한 기능을 플러그인(plugin)으로 확장한다.
plugins {
    id 'java'
	id 'org.springframework.boot' version '3.5.4'
	id 'io.spring.dependency-management' version '1.1.7'
}
  • java: Java 프로젝트 구조와 컴파일 규칙 적용
  • org.springframework.boot: Spring Boot 프로젝트로 인식, bootRun, bootJar 같은 부트 관련 태스크 제공
  • io.spring.dependency-management: Spring에서 BOM 방식으로 의존성 버전 관리 가능하게 함

의존성 설정

  • Spring Boot는 다양한 스타터 의존성을 제공해 쉽게 라이브러리를 추가할 수 있다.
  • 해당 의존성이 추가 된 경우 Gradle이 자동으로 감지하여 라이브러리를 추가한다.
  • 만일 추가되지 않는 다면 Gradle 에서 Sync 기능을 활용하여 수동으로 추가 가능
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    runtimeOnly 'com.h2database:h2'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
  • implementation : 애플리케이션 코드에서 직접 사용하는 라이브러리 (예: spring-boot-starter-web, thymeleaf)
  • compileOnly : 컴파일 시에만 필요한 라이브러리 (예: lombok)
  • developmentOnly : 개발 환경에서만 사용되는 라이브러리 (예: spring-boot-devtools)
  • runtimeOnly : 런타임에만 필요한 라이브러리 (예: H2 Database)
  • annotationProcessor : 어노테이션 처리용 라이브러리 (예: lombok)
  • testImplementation : 테스트 코드에서 사용하는 라이브러리 (예: spring-boot-starter-test)
  • testRuntimeOnly : 테스트 실행 시에만 필요한 라이브러리 (예: junit-platform-launcher)

태스크 설정

  • Gradle은 태스크(Task) 단위로 작업을 수행한다.
  • 필요에 따라 커스텀 태스크를 추가할 수도 있다.
tasks.named('test') {
	useJUnitPlatform()
}

tasks.register('hello') {
	doLast { println 'Hello Gradle!' }
}

Gradle 주요 명령어

Gradle은 애플리케이션 빌드, 실행, 테스트 수행, 의존성 트리 확인, 사용 가능한 작업 목록 조회, 빌드 결과 초기화와 같은 주요 기능을 제공한다.

명령어설명
./gradlew build전체 애플리케이션을 빌드 (컴파일 + 테스트 + 패키징)
./gradlew clean빌드 결과물(build/)을 삭제하여 초기화
./gradlew bootRun애플리케이션을 실행 (Spring Boot 전용)
./gradlew test테스트 코드 실행
./gradlew dependencies의존성 트리 확인
./gradlew tasks프로젝트에서 사용할 수 있는 모든 태스크 목록 출력

Gradle Wrapper

Gradle Wrapper(래퍼)는 Gradle이 설치되어 있지 않은 환경에서도 프로젝트를 동일한 Gradle 버전으로 빌드할 수 있도록 해주는 실행 도구이다. (절대 gitignore 하면 안된다!)

  • 구성: gradlew, gradlew.bat(실행 스크립트)와 gradle/wrapper/gradle-wrapper.properties(버전·다운로드 경로 설정)로 구성
  • 장점: 팀원이나 CI/CD 서버가 별도로 Gradle을 설치할 필요 없이, 프로젝트에 정의된 버전을 자동으로 다운로드·사용할 수 있음
  • 사용 목적: 환경 의존성을 줄이고 일관된 빌드 환경을 보장하기 위함

mvnrepository

Maven Repository(mvnrepository.com)는 Maven·Gradle 같은 빌드 도구가 사용하는 라이브러리
저장소를 검색할 수 있는 웹 서비스다. 개발자는 여기서 의존성 좌표(Group, Artifact, Version)를 확인해
빌드 스크립트에 추가할 수 있다. 즉, 외부 라이브러리 관리와 버전 확인을 쉽게 해주는 중앙 허브
역할을 한다.
→ mavenCentral()을 통해 의존성 파일은 실제 여기서 다운로드 된다.

Spring Boot - 설정 파일과 프로필

application.properties와 application.yaml의 역할

Spring Boot 애플리케이션의 환경 설정 파일로, 포트, DB 연결, 로깅, 프로필 등 실행 환경을 정의한다.
설정 파일은 Spring Boot가 자동으로 로드해 애플리케이션 실행 시 설정 값을 주입하는 역할을 한다.

  • .properties 키-값 쌍으로 단순하게 작성된다. (Legacy)
  • .yaml 계층적 구조로 가독성이 높아 복잡한 설정에 적합하다. (최근 권장)

프로필의 개념 및 프로필 설정 파일

프로젝트 프로필(Profile)은 개발·테스트·운영 등 환경별로 다른 설정을 적용하기 위한 논리적 구분이다.
application-{profile}.yml 형식으로 프로필별 설정 파일을 만들어 관리하며, 예를 들어 application-dev.yml, application-prod.yml처럼 구분한다.
jar파일 실행 시 --spring.profiles.active=dev 옵션이나 application.yml에서 spring.profiles.active로 활성화 할 프로필을 지정한다. (권장)

프로필 설정 파일의 우선순위

Spring Boot는 다양한 위치와 방식으로 설정 값을 로드 하며, 우선순위가 존재한다.

(낮음 → 높음)

  1. 기본 설정 파일
    • application.properties / application.yml
  2. 프로필별 설정 파일
    • application-{profile}.yml (예: application-dev.yml)
  3. 외부 설정 파일
    • --spring.config.location 또는 --spring.config.additional-location 으로 지정
  4. 환경 변수
    • OS나 Docker/Kubernetes 환경에서 주입
  5. 명령줄 인자
    • --server.port=9090 형태로 실행 시 직접 지정 (가장 높은 우선순위)

뒤에서 읽은 값이 앞의 값을 덮어씀(Override)

public git 활용 시 주의사항

application.yml 같은 설정 파일을 공개 저장소(GitHub 등)에 업로드하면 도메인 계정 비밀번호나 API Key 같은 민감 정보가 그대로 노출될 위험이 있다. (실제 이것만 스캔하는 bot이 수백개다)

  1. 환경 변수(.env)나 외부 Secret Manager(AWS Secrets Manager, Vault 등)에 민감정보를 분리 저장하고, yml에는 참조만 남긴다.
  2. gitignore로 로컬 설정 파일 제외하거나, 암호화된 설정 관리 도구(Jasypt 등)를 사용해 민감정보를 암호화 저장한다.

Spring Boot 애플리케이션의 시작

Spring Boot 애플리케이션의 시작

Spring Boot 애플리케이션은 main 메서드를 포함하는 진입 클래스로부터 실행된다.
진입 클래스에는 @SpringBootApplication이 선언되며, 이 어노테이션을 통해 핵심적인 부트스트랩 과정이 수행된다. 실행 시 SpringApplication.run() 메서드를 호출하여 애플리케이션 컨텍스트를 초기화하고, 자동 설정과 빈 등록을 포함한 구동 절차가 진행된다.
@SpringBootApplication 어노테이션 선언 순서에 따라 Config → AutoConfig → Scan이 수행된다.

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
public @interface SpringBootApplication {}
  1. @SpringBootConfiguration
    • 내부적으로 @Configuration을 포함한다.
    • 이 클래스가 스프링 컨테이너 설정 클래스임을 의미한다.
    • 즉, 빈(Bean)을 등록하는 구성 클래스 역할
  2. @EnableAutoConfiguration
    • 자동 설정(Auto-Configuration)을 활성화.
    • classpath에 있는 라이브러리를 확인해 적절한 기본 설정을 자동으로 적용
      • 예: spring-boot-starter-web이 있으면 내장 톰캣 + Spring MVC 자동 설정
      • spring-boot-starter-data-jpa가 있으면 JPA + Hibernate 설정 자동 구성
    • 커스터마이징 가능: @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})처럼 특정 자동 설정 제외 가능
  3. @ComponentScan
    • 현재 패키지와 하위 패키지를 스캔해 빈(Bean)을 자동으로 등록
    • 예: @Controller, @Service, @Repository, @Component로 선언된 클래스가 자동 등록
    • 스캔 범위 조정 가능: @SpringBootApplication(scanBasePackages = "com.example.myapp")

Spring Boot 애플리케이션의 시작 순서

실행 시 동작 흐름

  1. 메인 메서드에서 SpringApplication.run() 호출.
  2. @SpringBootApplication → 내부적으로 아래 내용 실행
    @SpringBootConfiguration: 설정 클래스 인식
    @EnableAutoConfiguration: 라이브러리 기반 자동 설정
    @ComponentScan: 패키지 하위 클래스 자동 스캔 및 빈 등록
  3. ApplicationContext 생성
    빈 초기화 → 내장 톰캣 구동 → 애플리케이션 준비 완료

애플리케이션 실행 프로세스

애플리케이션 컨텍스트 생성 단계

  1. 애플리케이션 컨텍스트 생성 단계
    • SpringApplication.run() 호출 시 SpringApplication 객체가 초기화되고 ApplicationContext가 생성된다.
    • 기본적으로 AnnotationConfigServletWebServerApplicationContext(웹) 또는 AnnotationConfigApplicationContext(비웹)가 사용된다.
    • 이 과정에서 환경(Environment), 리스너, 초기화기(ApplicationContextInitializer) 등이 먼저 등록된다.
  2. 자동 설정 적용 과정
    • @EnableAutoConfiguration이 활성화되어 SpringFactoriesLoader를 통해 spring.factories에 정의된 자동 설정 클래스를 읽어온다.
    • 조건부 애노테이션(@ConditionalOnClass, @ConditionalOnMissingBean 등)을 검사하여 현재 환경에 맞는 Bean만 등록한다.
    • 예: 데이터베이스 드라이버가 있으면 DataSourceAutoConfiguration이 동작
  3. Bean 등록 과정과 순서
    • 컴포넌트 스캔(@ComponentScan) 으로 패키지 내의 @Component, @Service, @Repository, @Controller 등을 찾아 Bean으로 등록
    • Java Config 클래스(@Configuration) 의 @Bean 메서드가 실행되어 Bean 생성
    • AutoConfiguration Bean이 마지막으로 병합되어 등록 (사용자 정의 > 자동설정 순서로 우선순위 적용)
  4. 이벤트 리스너와 생명주기 콜백
    • 실행 중 ApplicationEvent(ApplicationStartedEvent, ApplicationReadyEvent 등)가 순차적으로 발행된다.
    • 개발자는 @EventListenerApplicationListener로 실행 단계별 로직을 추가할 수 있다.
    • Bean은 초기화 단계에서 InitializingBean.afterPropertiesSet() 또는 @PostConstruct 호출, 종료 시 DisposableBean.destroy() 또는 @PreDestroy가 실행된다.

Bean 생명주기

  1. 스프링 컨테이너 생성 : ApplicationContext 초기화로 Bean 관리 환경 준비
  2. 스프링 빈 생성 : Bean 정의에 따라 객체 인스턴스화
  3. 의존관계 주입 : @Autowired, 생성자, 세터를 통한 의존성 주입
  4. 초기화 콜백 : @PostConstruct 또는 afterPropertiesSet() 실행
  5. 사용 : 애플리케이션 로직에서 Bean 활용
  6. 소멸전 콜백 : @PreDestroy 또는 destroy()로 종료 전 처리
  7. 스프링 종료 : 컨테이너 종료와 함께 Bean 소멸

Starter / 의존성 관리 심화

spring-boot-starter

spring-boot-starter는 스프링 부트 애플리케이션의 실행을 위한 공통 기본 의존성 묶음이다.
로깅(Logback), 자동 설정(AutoConfiguration), YAML 파서 등 부트 구동에 필요한 필수 모듈을 포함한다.
웹·JPA 등 특정 기능은 없고, 다른 스타터들의 기반이 되는 최소 스타터 역할을 한다.

  • 주요 start 의존성
    • spring-boot : 스프링 부트 애플리케이션의 핵심 클래스와 런타임 지원
    • spring-boot-autoconfigure : 애플리케이션 환경에 따라 자동으로 Bean과 설정을 적용
    • spring-boot-starter-logging : SLF4J 인터페이스와 Logback 구현체를 통한 기본 로깅 제공
    • spring-core / spring-context / spring-beans / spring-expression : 스프링 프레임워크의 핵심 기능 (DI, 컨텍스트 관리, SpEL 등)
    • org.yaml:snakeyaml : YAML 형식의 설정 파일(application.yml) 파싱 지원

spring-boot-starter-web

spring-boot-starter-web은 Spring MVC 기반 웹 애플리케이션 개발을 위한 스타터다.
내장 Tomcat을 통해 별도의 WAS 없이 바로 실행 가능한 환경을 제공한다. REST API, JSON 처리, 검증 등 웹 개발 필수 모듈을 자동으로 포함한다.

  • 주요 start 의존성
    • Spring MVC : DispatcherServlet 기반 요청-응답 처리 및 REST API 구현 지원
    • Jackson : 자바 객체와 JSON 간 직렬화·역직렬화 처리
    • Embedded Tomcat : 애플리케이션 내부에서 실행되는 내장형 서블릿 컨테이너
    • Hibernate Validator : JSR-380 기반 요청 파라미터 및 객체 검증 기능
    • Spring Web : REST 클라이언트/서버 개발을 위한 HTTP 통신 모듈

spring-boot-starter-test

spring-boot-starter-test는 스프링 부트 애플리케이션 테스트를 위한 통합 스타터다.
단위 테스트, 통합 테스트, Mock 객체 기반 테스트를 위한 주요 라이브러리를 자동 포함한다.
JUnit, Mockito, Spring Test 등 표준 테스트 도구를 한 번에 제공한다.

  • 주요 start 의존성
    • JUnit : 자바 표준 단위 테스트 프레임워크
    • Spring Test : 스프링 컨텍스트 기반 통합 테스트 지원
    • Mockito : 의존성 모킹(Mock) 객체 생성을 위한 프레임워크
    • Hamcrest : 가독성 높은 조건 매칭(assertThat) 지원
    • AssertJ : 체이닝 기반의 직관적인 단언문 API
    • JSONassert : JSON 응답 구조 및 값 검증 도구
    • Spring Boot Test : @SpringBootTest 등 부트 애플리케이션 테스트 전용 유틸리티

버전 관리와 호환성 보장

버전 관리와 호환성 보장

Spring Boot는 BOM(Bill of Materials) 방식을 사용해, 의존성 라이브러리들의 버전을 일괄 관리하고
호환성을 보장한다. 개발자가 개별 라이브러리 버전을 명시하지 않아도, Spring Boot가 테스트·검증한
안정된 버전 세트를 자동 적용

spring-boot-dependencies의 역할

spring-boot-dependencies는 Spring Boot 프로젝트에서 사용하는 BOM으로, 모든 Starter 및 주요
서드파티 라이브러리(Jackson, Tomcat, Hibernate 등)의 버전을 통합 관리한다.
Gradle/Maven에서 별도 버전을 지정하지 않으면 이 BOM에 정의된 기본 버전이 사용됨

의존성 관리 심화

  1. 의존성 제외와 대체 (Exclusion & Replacement)
    예: spring-boot-starter-web 기본 내장 Tomcat을 제외하고 Jetty로 교체
    dependencies {
        implementation('org.springframework.boot:spring-boot-starter-web') {
            exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
        }
        implementation 'org.springframework.boot:spring-boot-starter-jetty'
    }
  2. 선택적 의존성 추가 (Optional Dependency)
    예: JPA Starter 사용 시 기본 DB 드라이버는 포함되지 않음, 직접 추가
    dependencies {
        implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
        runtimeOnly 'com.mysql:mysql-connector-j'
    }
  3. 버전 오버라이딩
    예: BOM에서 관리하는 Jackson 버전을 최신으로 교체
    dependencies {
        implementation 'org.springframework.boot:spring-boot-starter-web'
        implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.0' // 오버라이딩
    }

레이어드 아키텍처의 이해

레이어드 아키텍처의 개념

Spring Boot 애플리케이션은 관심사 분리(Separation of Concerns)를 위해 레이어드 아키텍처 패턴을
주로 사용한다. 각 계층은 명확한 책임을 가지고, 아래 계층에만 의존하는 구조를 갖는다.

  1. 프레젠테이션 레이어 (Controller)
    • 책임: 클라이언트 요청(Request)을 받아 적절한 서비스 호출 후 응답(Response) 반환
    • Spring 구성요소: @Controller, @RestController
    • 주요 역할: URL 매핑, HTTP 요청 파라미터 처리, 뷰 렌더링 또는 JSON 반환
  2. 비즈니스 레이어 (Service)
    • 책임: 비즈니스 로직 처리, 트랜잭션 관리
    • Spring 구성요소: @Service
    • 주요 역할: 도메인 규칙 구현, 여러 Repository 조합 처리, 재사용 가능한 로직 제공
  3. 퍼시스턴스 레이어 (Persistence)
    • 책임: 데이터 저장소(DB)와의 연동 담당
    • Spring 구성요소: @Repository
    • 주요 역할: JPA/Hibernate 등을 통한 CRUD 처리, 예외 변환(DataAccessException)
  4. 데이터베이스 레이어 (DB)
    • 책임: 실제 데이터가 저장되는 물리적 저장소
    • Spring 구성요소: DataSource, JPA EntityManager 등이 활용

주요 Spring 컴포넌트 소개 및 계층간 의존성 관계

@Controller 웹 요청/응답을 처리하는 컨트롤러 (MVC, View가 있을 때 사용)
@RestController 웹 요청/응답을 처리하는 컨트롤러 (REST, View가 없을 때 사용)
@Service 핵심 비즈니스 로직 담당, 트랜잭션 및 도메인 규칙 구현
@Repository 데이터 접근 계층, SQL/JPA를 통한 데이터 연산 처리
(@RestController = @Controller + @ResponseBody)

계층 간 의존성 관계

  • 흐름: Controller → Service → Repository → DB
  • 단방향 의존성: 상위 계층이 하위 계층에만 의존
  • 응답 흐름: DB → Repository → Service → Controller → 클라이언트

이벤트 기반 아키텍처의 이해

이벤트 기반 프로그래밍의 개념

이벤트 기반 아키텍처(Event-Driven Architecture)는 특정 동작이 발생했을 때(이벤트) 이를 비동기적으로 처리하는 구조를 말한다. 핵심은 발생(Producer) 과 처리(Consumer) 를 느슨하게 연결해 확장성과 유연성을 높이는 것이다.

  • 핵심: 어떤 동작(이벤트)이 발생하면 등록된 핸들러(리스너)가 자동으로 호출되어 처리
  • 특징: 발행자(Publisher)와 구독자(Listener)가 직접적으로 의존하지 않음 (loose coupling)
  • 활용: 도메인 이벤트(회원가입, 결제 완료 등), 알림 처리, 비동기 로깅 등

Spring의 이벤트 처리 구조

Spring Boot에서 이벤트 기반 아키텍처는 ApplicationEventPublisher와 @EventListener 를 활용해 발행-
구독 구조로 동작하며, 비즈니스 로직을 느슨하게 결합하고 비동기적 처리를 가능하게 한다.

  • ApplicationEventPublisher : 애플리케이션 내에서 이벤트를 발행(Publish)하는 컴포넌트
  • ApplicationEvent : 발행할 이벤트를 표현하는 객체 (이벤트 데이터 보관)
  • @EventListener : 발행된 이벤트를 수신(Listen)해 처리하는 메서드에 사용하는 어노테이션
profile
Backend engineer

0개의 댓글