본문으로 건너뛰기
AIDevOps
  • Learn
  • Learning Paths
  • Practice
  • Open Source
  • Books
  • Engineering

    AI DevOpsAI 서비스 개발·운영 전체 지도LLMOpsLLM 배포·평가·관측실전 프로젝트AI Agent 프로젝트 실습

    Knowledge

    Docs기술 문서 모음Blog엔지니어링 아티클Plogger개발 기록 피드

    Validate

    Certification3단계 역량 인증 · 준비 중
AI Models
LlamaMistralGemmaDeepSeekQwen
🌱 Spring Cloud
Spring 입문 & 로드맵Spring Cloud GatewaySpring BootJava|Spring AISpring SecuritySpring BatchSpring JPA
🤖 AI 실전 개발
AI 실전 입문 & 로드맵Hugging FaceLangChainLlamaIndexLLMOps|LangGraphMCPMulti-AgentAgent Evaluation
🧠 AI Core
AI 입문 & 로드맵ML FundamentalsLLM Fundamentals|Python AIC++|PyTorchTensorFlowJAX
🧠 AI Agent 개발
금융 AI AgentLLM API 서버주식 투자 AgentAIOps AI Agent교육 AI Agent코딩 AI Agent
🐳 DevOps
DevOps 입문 & 로드맵LinuxDockerCI/CD|Kubernetes 기본K8s 심화/실무PrometheusGrafana
🧱 인프라
인프라 입문 & 로드맵NginxRedis
☁️ 클라우드
클라우드 입문 & 로드맵AWSGCPAzureNCPCloudflare
🎨 Frontend
Frontend 입문 & 로드맵JavaScriptTypeScript|ReactNext.js|VueNuxt
📱 Mobile
Mobile 입문 & 로드맵KotlinAndroidFlutter
⚙️ Backend
Backend 입문 & 로드맵Python 기본FastAPIDjangoFlask|CGoGinNode.js
💾 Database
DB 입문 & 로드맵공통 SQLOracleMySQLPostgreSQL|MongoDB벡터 DB
🧪 검증
k6JMeternGrinder
AIDevOps

Engineering AI. From Code to Production.
AI와 AI Agent를 개발하고 운영하기 위한 엔지니어링 학습 플랫폼

Learn

  • 전체 가이드
  • Learning Paths
  • Practice
  • Books

Resources

  • AI DevOps
  • LLMOps
  • 실전 프로젝트
  • Docs
  • Blog
  • Plogger
  • Open Source
  • Certification (준비 중)

Start Here

  • AI Core 로드맵
  • AI 실전 개발 로드맵
  • Spring Cloud 로드맵
  • DevOps 로드맵
  • 인프라 로드맵

 

  • 클라우드 로드맵
  • Frontend 로드맵
  • Mobile 로드맵
  • Backend 로드맵
  • Database 로드맵
© 2026 AI DevOps Korea. All rights reserved.
이용약관개인정보처리방침Sitemaptestforge.kr
  1. Home
  2. Learn
  3. Spring Cloud
  4. Spring Boot
Java 프레임워크 가이드

🍃 Spring Boot 완전 가이드

Visitors

Java 생태계 표준 백엔드 프레임워크. IoC/DI, REST API, JPA, Spring Security, 테스트, Docker 배포까지 실무 중심으로 정리했습니다.

  • Intermediate · 중급
  • 업데이트 2026.09.19
  • 약 13분 읽기
  • 13개 섹션
  • 예제 코드 8개
  • 웹 IDE 실습 제공
🍃

Spring Boot 웹 IDE

설치 없이 브라우저에서 코드를 실행하고 단계별 예제로 익혀보세요.

웹 IDE 열기 →
REST API 서버JPA/Hibernate ORMSpring Security JWTMSA 백엔드

관련 프레임워크 & 개발환경

☕Java→GWSpring Cloud Gateway→🔐Spring Security→🗄️Spring JPA→⚙️Spring Batch→

목차

0 / 15
  1. 가이드 사용법
  2. 구조 다이어그램
  3. Spring Boot란?
  4. 프로젝트 생성
  5. 첫 번째 REST API
  6. DI / IoC
  7. REST API 완전 설계
  8. Spring Data JPA
  9. 예외 처리
  10. Spring Security (JWT)
  11. 테스트 (JUnit + MockMvc)
  12. Docker 배포
  13. Spring Boot 설계
  14. 운영 기준
  15. 검증 전략
목차 15개 섹션
  1. 가이드 사용법
  2. 구조 다이어그램
  3. Spring Boot란?
  4. 프로젝트 생성
  5. 첫 번째 REST API
  6. DI / IoC
  7. REST API 완전 설계
  8. Spring Data JPA
  9. 예외 처리
  10. Spring Security (JWT)
  11. 테스트 (JUnit + MockMvc)
  12. Docker 배포
  13. Spring Boot 설계
  14. 운영 기준
  15. 검증 전략

가이드 사용법

읽는 방향

Spring Boot를 실무 흐름으로 이해하기

Java 생태계 표준 백엔드 프레임워크. IoC/DI, REST API, JPA, Spring Security, 테스트, Docker 배포까지 실무 중심으로 정리했습니다. 이 가이드는 개념을 나열하기보다, 실제 프로젝트에서 판단해야 하는 순서대로 내용을 따라갈 수 있게 구성했습니다.

핵심 관점

백엔드 / 시스템 개발

문법보다 요청이 들어와 검증, 처리, 저장, 응답으로 이어지는 경계를 먼저 잡습니다.

REST API 서버JPA/Hibernate ORMSpring Security JWTMSA 백엔드

구조 다이어그램

글로 읽은 내용을 머릿속에 오래 남기려면 먼저 흐름을 그림으로 잡는 편이 좋습니다. 아래 두 그림은 Spring Boot를 학습할 때 계속 되돌아볼 수 있는 기준 지도입니다.

학습 흐름

다이어그램 렌더링 중…

아키텍처 관점

다이어그램 렌더링 중…

Spring Boot란?

Spring Boot를 처음 펼칠 때는 세부 명령보다 큰 그림이 먼저입니다. 이 섹션에서는 앞으로 배울 개념들이 어떤 문제를 풀기 위해 등장했는지부터 잡아봅니다.

Spring Boot는 Auto-Configuration과 내장 서버를 제공하여 복잡한 XML 설정 없이 프로덕션 수준 애플리케이션을 빠르게 개발할 수 있는 프레임워크입니다.
특징설명
Auto-Configuration의존성만 추가하면 자동 설정
내장 서버Tomcat 내장 — JAR 하나로 실행
Spring Initializrstart.spring.io에서 즉시 생성
Actuator헬스체크·메트릭 엔드포인트 기본 제공

프로젝트 생성

여기서는 프로젝트 생성을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

Spring Initializr(start.spring.io)에서 빌드 도구와 의존성을 선택해 프로젝트 뼈대를 바로 생성할 수 있습니다. Gradle Kotlin DSL은 설정 자동완성과 타입 검사가 되어 대규모 프로젝트에서 Groovy DSL보다 유지보수가 쉽습니다.
BASH
# start.spring.io → Gradle Kotlin, Java 21, 의존성:
# Spring Web, Spring Data JPA, Spring Security
# H2 Database, Lombok, Validation

./gradlew bootRun   # 실행
./gradlew bootJar   # 빌드

첫 번째 REST API

여기서는 첫 번째 REST API을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

@RestController는 메서드의 반환값을 자동으로 JSON으로 직렬화해 응답 본문에 담아주고, @RequestMapping은 이 컨트롤러가 처리할 기본 URL 경로를 지정합니다. 페이지네이션이 필요한 목록 조회는 Page 반환 타입 하나로 페이지 번호·전체 개수 같은 메타데이터까지 함께 내려줄 수 있습니다.
JAVA
@RestController
@RequestMapping("/api/v1/users")
@RequiredArgsConstructor
public class UserController {
    private final UserService userService;

    @GetMapping
    public Page<UserResponse> list(@RequestParam(defaultValue="0") int page) {
        return userService.findAll(PageRequest.of(page, 20));
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public UserResponse create(@Valid @RequestBody CreateUserRequest req) {
        return userService.create(req);
    }
}

DI / IoC

여기서는 DI / IoC을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

Spring의 핵심은 IoC(Inversion of Control) 컨테이너입니다. 객체(Bean)를 개발자가 직접 `new`로 생성하는 대신, 컨테이너가 필요한 의존성을 미리 만들어두고 필요한 곳에 주입(DI)해줍니다. 이 덕분에 클래스는 "내가 무엇을 쓸지"만 선언하면 되고, "그것을 어떻게 만들지"는 신경 쓰지 않아도 됩니다.
ConstructorInjection.javaJAVA
// 권장: 생성자 주입 — final로 불변성 보장, 테스트 시 mock 주입이 쉬움
@Service
@RequiredArgsConstructor   // Lombok이 final 필드를 받는 생성자를 자동 생성
public class OrderService {
    private final PaymentClient paymentClient;
    private final OrderRepository orderRepository;

    public Order placeOrder(OrderRequest req) {
        paymentClient.charge(req.amount());
        return orderRepository.save(Order.from(req));
    }
}

// 비권장: 필드 주입 — final 불가, 테스트 시 리플렉션 없이는 mock 주입 불가
@Service
public class LegacyOrderService {
    @Autowired
    private PaymentClient paymentClient;
}
주입 방식특징권장 여부
생성자 주입final 필드 사용 가능, 필수 의존성을 명확히 드러냄, 순환 참조를 컴파일 시점에 발견권장
세터 주입선택적 의존성에 적합, 런타임에 재설정 가능제한적으로 사용
필드 주입코드는 짧지만 불변성 보장 불가, 순수 단위 테스트 작성이 어려움지양

Tip

@Autowired를 필드에 직접 붙이는 대신 생성자 주입 + Lombok의 @RequiredArgsConstructor 조합을 기본값으로 삼으세요 — Spring 팀도 공식적으로 생성자 주입을 권장합니다.

REST API 완전 설계

여기서는 REST API 완전 설계을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

Controller는 HTTP 요청/응답 변환만 담당하고, 실제 비즈니스 로직은 Service에, 데이터 접근은 Repository에 위임하는 3계층 구조가 기본입니다. 각 계층은 자신의 바로 아래 계층만 호출해야 하며, Controller가 Repository를 직접 호출하는 식으로 계층을 건너뛰면 나중에 로직을 재사용하거나 테스트하기 어려워집니다.
다이어그램 렌더링 중…
HTTP 상태 코드사용 시점
200 OK조회·수정 성공, 응답 본문 있음
201 Created생성 성공 — Location 헤더에 새 리소스 URI 포함 권장
204 No Content삭제 성공 등 응답 본문이 없는 성공
400 Bad Request요청 값 검증 실패 (@Valid 실패 등)
404 Not Found요청한 리소스가 존재하지 않음
409 Conflict중복 생성, 낙관적 락 충돌 등 상태 충돌

Tip

Entity를 그대로 응답에 반환하지 말고 별도 Response DTO로 변환하세요 — Entity의 연관관계(지연 로딩)가 그대로 JSON 직렬화되며 원치 않는 쿼리나 순환 참조 오류로 이어지기 쉽습니다.

Spring Data JPA

여기서는 Spring Data JPA을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

JpaRepository를 상속하는 것만으로 save, findById, delete 같은 기본 CRUD 메서드가 자동으로 생기고, findByEmail처럼 메서드 이름을 규칙에 맞게 지으면 Spring이 이름을 분석해 SQL을 알아서 생성해줍니다. 별도의 SQL이나 구현체 없이 인터페이스 선언만으로 데이터 접근 계층을 완성할 수 있는 것이 핵심입니다.
JAVA
@Entity @Table(name="users")
@Getter @Builder @NoArgsConstructor @AllArgsConstructor
public class User {
    @Id @GeneratedValue(strategy=IDENTITY) private Long id;
    @Column(nullable=false)               private String name;
    @Column(nullable=false, unique=true)  private String email;
    @CreationTimestamp private LocalDateTime createdAt;
}

public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByEmail(String email);
    boolean existsByEmail(String email);
}

예외 처리

여기서는 예외 처리을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

컨트롤러마다 try-catch를 반복하는 대신, `@RestControllerAdvice`로 애플리케이션 전역의 예외를 한곳에서 잡아 일관된 형식의 에러 응답으로 변환합니다. 이렇게 하면 클라이언트는 어떤 API를 호출하든 항상 같은 모양의 에러 응답을 받게 됩니다.
GlobalExceptionHandler.javaJAVA
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(EntityNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleNotFound(EntityNotFoundException ex) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND)
            .body(new ErrorResponse("NOT_FOUND", ex.getMessage()));
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ErrorResponse> handleValidation(MethodArgumentNotValidException ex) {
        String message = ex.getBindingResult().getFieldErrors().stream()
            .map(err -> err.getField() + ": " + err.getDefaultMessage())
            .collect(Collectors.joining(", "));
        return ResponseEntity.badRequest().body(new ErrorResponse("VALIDATION_ERROR", message));
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleUnexpected(Exception ex) {
        log.error("Unhandled exception", ex);   // 원인 파악을 위해 반드시 로그에 스택트레이스 남기기
        return ResponseEntity.internalServerError()
            .body(new ErrorResponse("INTERNAL_ERROR", "일시적인 오류가 발생했습니다"));
    }
}

record ErrorResponse(String code, String message) {}

Tip

Exception.class를 잡는 마지막 핸들러에서는 원본 예외 메시지를 그대로 클라이언트에 노출하지 마세요 — 내부 구현 정보(SQL, 클래스명 등)가 새어나갈 수 있습니다. 대신 서버 로그에는 스택트레이스를 남기고, 클라이언트에는 일반화된 메시지만 반환하세요.

Spring Security (JWT)

여기서는 Spring Security (JWT)을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

JWT(JSON Web Token) 인증은 서버가 세션을 저장하지 않는 stateless 방식입니다. 로그인 시 서버가 서명된 토큰을 발급하고, 이후 요청마다 클라이언트가 그 토큰을 Authorization 헤더에 담아 보내면 필터가 서명을 검증해 누구의 요청인지 판별합니다.
다이어그램 렌더링 중…
SecurityConfig.javaJAVA
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
    private final JwtAuthFilter jwtAuthFilter;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http
            .csrf(AbstractHttpConfigurer::disable)   // stateless API는 CSRF 토큰 불필요
            .sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/login", "/api/signup").permitAll()
                .anyRequest().authenticated())
            .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
            .build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

Tip

  • JWT는 발급 후 서버가 그 존재를 따로 기억하지 않기 때문에, 로그아웃이나 강제 무효화가 세션 방식보다 까다롭습니다 — 짧은 만료 시간 + Refresh Token 조합이나 블랙리스트를 함께 고려하세요.
  • 토큰은 브라우저의 localStorage보다 httpOnly 쿠키에 저장하는 편이 XSS 공격으로부터 더 안전합니다.

테스트 (JUnit + MockMvc)

여기서는 테스트 (JUnit + MockMvc)을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

단위 테스트는 Service 계층의 로직을 Mockito로 의존성을 가짜로 대체해 빠르게 검증하고, 통합 테스트는 `@SpringBootTest`나 `@WebMvcTest`로 실제 스프링 컨텍스트를 띄워 컨트롤러부터 검증합니다. 두 종류를 구분해서 작성하면, 로직 버그는 빠른 단위 테스트로, API 계약(요청/응답 형식)은 통합 테스트로 각각 효율적으로 잡을 수 있습니다.
OrderControllerTest.javaJAVA
@WebMvcTest(OrderController.class)
class OrderControllerTest {
    @Autowired MockMvc mockMvc;
    @MockBean OrderService orderService;

    @Test
    void 주문_생성_성공() throws Exception {
        given(orderService.placeOrder(any())).willReturn(new Order(1L, 10000));

        mockMvc.perform(post("/api/v1/orders")
                .contentType(MediaType.APPLICATION_JSON)
                .content("""
                    {"productId": 1, "amount": 10000}
                """))
            .andExpect(status().isCreated())
            .andExpect(jsonPath("$.id").value(1));
    }

    @Test
    void 검증_실패시_400() throws Exception {
        mockMvc.perform(post("/api/v1/orders")
                .contentType(MediaType.APPLICATION_JSON)
                .content("{}"))
            .andExpect(status().isBadRequest());
    }
}
테스트 종류범위속도대표 애너테이션
단위 테스트Service 로직 하나 (의존성은 Mockito로 대체)매우 빠름@ExtendWith(MockitoExtension.class)
웹 계층 테스트Controller + 요청/응답 직렬화빠름@WebMvcTest
통합 테스트전체 스프링 컨텍스트 + 실제 DB(H2 등)느림@SpringBootTest

Tip

모든 테스트를 @SpringBootTest로만 작성하면 스프링 컨텍스트를 매번 새로 띄우느라 테스트 스위트 전체가 느려집니다 — 로직 검증은 단위 테스트로, 계층 간 연동 확인만 통합 테스트로 좁혀서 실행 시간을 관리하세요.

Docker 배포

여기서는 Docker 배포을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

멀티스테이지 빌드로 빌드 단계(JDK)와 실행 단계(JRE)를 분리하면 최종 이미지에 컴파일 도구가 남지 않아 이미지 크기가 크게 줄어듭니다. 의존성 다운로드(gradlew dependencies)를 소스 복사보다 먼저 실행하면, 소스만 바뀌었을 때 의존성 레이어를 캐시에서 재사용해 빌드 속도도 빨라집니다.
DOCKERFILE
FROM eclipse-temurin:21-jdk-alpine AS builder
WORKDIR /app
COPY gradlew build.gradle.kts settings.gradle.kts ./
COPY gradle ./gradle
RUN ./gradlew dependencies --no-daemon
COPY src ./src
RUN ./gradlew bootJar --no-daemon

FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY --from=builder /app/build/libs/*.jar app.jar
USER nobody
EXPOSE 8080
ENTRYPOINT ["java","-jar","app.jar"]

Tip

USER nobody로 컨테이너 안에서 root가 아닌 계정으로 애플리케이션을 실행하면, 컨테이너가 뚫리더라도 공격자가 호스트에 영향을 줄 수 있는 권한을 얻기 어려워집니다.

Spring Boot 실무 설계

Spring Boot 실무 설계은 선택지가 갈리는 지점입니다. 표를 기준으로 각 방법의 쓰임새와 운영상의 차이를 비교해두면 이후 판단이 훨씬 쉬워집니다.

Spring Boot는 자동 설정을 이해하고 필요한 부분만 명시적으로 override해야 합니다. Controller-Service-Repository를 넘어서 transaction boundary와 domain event 설계가 중요합니다.
결정 지점확인 질문실무 기준
경계Spring Boot 코드에서 바뀌기 쉬운 부분은 어디인가?입출력, 설정, 외부 연동, 핵심 규칙을 분리합니다.
상태상태가 어디서 생성되고 어디서 사라지는가?상태 소유자와 수명 주기를 코드로 드러냅니다.
장애실패했을 때 호출자는 무엇을 받는가?timeout, fallback, error contract를 먼저 정합니다.

Spring Boot 운영 기준

이 섹션은 Spring Boot 운영 기준을 실무 관점에서 정리합니다. 개념을 외우기보다, 어떤 상황에서 이 기준을 꺼내 쓸지에 초점을 맞춰보세요.

Actuator, Micrometer, profile, graceful shutdown, connection pool 설정을 운영 기본값으로 봐야 합니다.

Tip

  • transaction boundary
  • Actuator health
  • profile config
  • slice tests

Spring Boot 검증 전략

Spring Boot 검증 전략은 선택지가 갈리는 지점입니다. 표를 기준으로 각 방법의 쓰임새와 운영상의 차이를 비교해두면 이후 판단이 훨씬 쉬워집니다.

@SpringBootTest 남용을 줄이고 slice test, contract test, Testcontainers로 목적별 테스트를 구성해야 합니다.
품질 축검증 방법완료 기준
정확성정상/실패 케이스를 자동화합니다.핵심 시나리오가 재현 가능하게 통과합니다.
회귀 방지버그 수정 시 동일 케이스를 테스트로 남깁니다.같은 장애가 다시 배포되지 않습니다.
운영성로그, 메트릭, 알림을 확인합니다.문제가 생겼을 때 원인 추적 경로가 있습니다.
← 이전 가이드Spring Cloud Gateway다음 가이드 →Java