스프링(Spring), 스프링부트(SpringBoot)/스프링부트(SpringBoot) 기초

스프링 부트 핵심 가이드(장정우 지음) - 개발에 앞서 알면 좋은 기초 지식

개발학생 2025. 7. 11. 14:36
반응형

1. 서버 간 통신

  • 마이크로서비스 아키텍처에서 한 서버가 다른 서버에 통신을 요청하는 것을 의미
    -> 한 대는 서버/다른 한 대는 클라이언트가 됨 
  • 가장 많이 사용되는 방식은 HTTP/HTTPS 방식(TCP/IP, SOAP 방식도 있음) 

*마이크로서비스 아키텍처(MSA: Microservice Architecture)

  • 서비스 규모를 작게 나누어 구성한 아키텍처
    -> 애플리케이션 하나에 여러 기능을 넣지 않고, 블로그 프로젝트/카페 프로젝트/메일 프로젝트 등으로 나누어 개발
  • 사용자가 블로그 기능을 사용하기 위해 로그인 기능을 거치려면 두 기능 간 통신이 필요

단일 서비스 아키텍처 vs 마이크로서비스 아키텍처

 

2. 스프링 부트의 동작 방식

* 핸들러 매핑이란?

  • 요청 정보를 기준으로 어떤 컨트롤러를 사용할지 선정하는 인터페이스
  • 핸들러 매핑 인터페이스는 여러 구현체를 가지며, 대표적인 구현체 클래스는 다음과 같음
BeanNameUrlHandlerMapping - 빈 이름을 URL로 사용하는 매핑 전략
- 빈을 정의할 때 슬래시(‘/’)가 들어가면 매핑 대상
  -> 예) @Bean(“/hello”)
ControllerClassNameHandlerMapping - URL과 일치하는 클래스 이름을 갖는 빈을 컨트롤러로 사용하는 전략
- 이름 중 Controller를 제외하고 앞 부분에 작성된 suffix를 소문자로 매핑
SimpleUrlHandlerMapping - URL 패턴에 매핑된 컨트롤러를 사용하는 전
DefaultAnnotationHandlerMapping - 어노테이션으로 URL과 컨트롤러를 매핑하는 방법

**스프링 부트의 동작 방식 이해

  • spring-boot-starter-web 모듈을 사용하면 기본적으로 톰캣(Tomcat)을 사용하는 스프링 MVC 구조를 기반으로 동작
  • 서블릿(Servlet): 클라이언트 요청을 처리하고 결과를 반환하는 자바 웹 프로그래밍 기술
    -> 서블릿 컨테이너(Servlet Contriner)
         : 스프링 부트에서 서블릿 객체를 생성/초기화/호출/종료하는 생명주기를 싱글톤 패턴으로 관리, 멀티 스레딩 지원 
  • 스프링에서는 DispatcherServlet이 서블릿 역할을 수행함
    • (1) DispatcherServlet 으로 요청(HttpServletRequest)이 들어오면 DispatcherServlet은 핸들러 매핑(Handler Mapping)을 통해 요청 URL에 매핑된 핸들러를 탐색[여기서 핸들러는 컨트롤러(Controller)를 의미]
    • (2) 핸들러 어댑터(HandlerAdapter)로 컨트롤러를 호출
    • (3) 핸들러 어댑터에 컨트롤러의 응답이 돌아오면 ModelAndView로 응답을 가공해 반환
    • (4) 뷰 형식으로 리턴하는 컨트롤러를 사용할 때는 뷰 리졸버(View Resolver)를 통해 뷰(View)를 받아 리턴
      스프링의 동작 구조 이미지(출처: https://djcho.github.io/springboot/spring-boot-chapter2-2/)

      • DispatcherServlet이 뷰를 사용하는 경우 동작 방식은 다음과 같음
        -> 뷰 리졸버에서 뷰의 렌더링 역할을 담당하는 뷰 객체 반환 

스프링의 동작 구조 이미지 - 뷰를 사용하는 경우(출처:  https://djcho.github.io/springboot/spring-boot-chapter2-2/)

  • 이 책의 스프링 부트에서는 @RestController를 사용하는 DispatcherServlet의 동작 방식을 사용

스프링 부트의 동작 구조 이미지 - @RestController를 사용하는 DispatcherServlet의 동작 방식 (출처:  https://djcho.github.io/springboot/spring-boot-chapter2-2/)

1) 메인 클래스 실행

  • @SpringBootApplication 어노테이션이 붙은 메인 클래스를 통해 실행
  • 내부적으로 @Configuration, @EnableAutoConfiguration, @ComponentScan 세 가지 어노테이션이 포함되어 있어 설정과 컴포넌트 검색을 자동으로 처리

2) SpringApplication 객체 초기화

  • SpringApplication.run() 메서드가 호출되어 애플리케이션 컨텍스트를 초기화하고, 필요한 설정을 로딩
  • 환경 설정(properties, YAML 등)도 이 단계에서 읽힘

3) 내장 톰캣(Web Server) 시작

  • 별도로 톰캣을 설치하지 않아도 되고, 실행 시 자동으로 웹 서버가 구동

4) 자동 구성(Auto Configuration)

  • @EnableAutoConfiguration 덕분에, 애플리케이션의 의존성 기반으로 필요한 설정을 자동으로 적용
  • 예: spring-boot-starter-web을 포함하면 DispatcherServlet 등이 자동으로 설정

5) Bean 등록 및 의존성 주입(DI)

  • @Component, @Service, @Repository, @Controller 등을 통해 Bean이 등록
  • @Autowired 등을 통해 필요한 Bean 주입

6) 요청 처리 및 응답

  • 클라이언트 요청이 들어오면 DispatcherServlet이 이를 처리하고, 적절한 Controller로 전달
  • Controller → Service → Repository 순으로 처리된 결과를 클라이언트에게 응답

3. 레이어드 아키텍처(Layered Architecture)

  • 애플리케이션의 컴포넌트를, 유사 관심사를 기준으로 레이어로 묶어 수평적으로 구성한 구조
  • 일반적으로 3/4계층을 사용하나, 설계에 따라 용어와 계층에 수가 달라지는 것

일반적인 레이어드 아키텍처 이미지 (출처:  https://djcho.github.io/springboot/spring-boot-chapter2-3/)

  • 하나의 애플리케이션에도 적용되지만, 애플리케이션 간의 관계를 설명하는 데도 사용
  • 특징
- 각 레이어는 가장 가까운 하위 레이어의 의존성을 주입받음
- 각 레이어는 관심사에 따라 묶여 있으며, 다른 레이어의 역할을 침범하지 않음
- 각 컴포넌트의 역할이 명확하므로 코드의 가독성과 기능 구현에 유리하
- 코드의 확장성이 좋아짐
- 각 레이어가 독립적으로 작성되면, 다른 레이어와의 의존성을 낮춰 단위 테스트에 용이

* 스프링 부트의 레이어드 아키텍처

스프링 부트의 레이어드 아키텍처 이미지 (출처:  https://djcho.github.io/springboot/spring-boot-chapter2-3/)

(1) 프레젠테이션 계층(UI/User Interface/유저 인터페이스 계층)

  • 애플리케이션의 최상단 계층으로, 클라이언트의 요청을 해석하고 응답하는 역할(클라이언트와의 접점)
  • 클라이언트로부터 데이터와 함께 요청을 받고, 처리 결과를 응답으로 전달 

(2) 비즈니스 계층(Service/서비스 계층)

  • 애플리케이션이 제공하는 기능을 정의하고, 세부 작업을 수행하는 도메인 객체를 통해 업무를 위임하는 역할을 수행
  • DDD(Domain-Driven-Design) 기반 아키텍처에서는 비즈니스 로직에 도메인이 포함되기도 하고,
    별도로 도메인 계층을 두기도 함 
  • 핵심 비즈니스 로직 구현: 트랜잭션 처리나 유효성 검사 등의 작업도 수행 

(3) 데이터 접근 계층(Persistence/영속 계층)

  • 데이터베이스에 접근하는 일련의 작업 수행
  • 보통 DAO가 수행하는데, Spring Data JPA에서는 DAO 역할을 리포지토리가 수행하므로 리포지토리로 대체

4. 디자인 패턴(Design Pattern)

  • 객체지향 설계에서 반복적으로 나타나는 문제를 해결하기 위한 정형화된 설계 방법
  • GoF(디자인 패턴을 구체화하고 체계화해서 분류한 4명의 인물) 디자인 패턴 분류 방식
유형 패턴 이름 설명
생성(Creational) 패턴
- 객체 생성에 사용되는 패턴
: 객체를 수정해도 호출부가 영향을 받지 않게 함
Singleton(싱글톤) 하나의 인스턴스만 생성되도록 보장
Factory Method(팩토리 메서드) 객체 생성 인터페이스를 정의하고 서브클래스가 인스턴스를 결정
Abstract Factory(추상 팩토리) 관련 객체를 생성할 수 있는 인터페이스를 제공
Builder(빌더) 복잡한 객체의 생성 과정을 단계적으로 분리
Prototype(프로토타입) 복제(clone)를 통해 객체 생성
구조(Structural) 패턴
- 객체를 조합해서 더 큰 구조를 만드는 패턴
Adapter(어댑터) 인터페이스 호환 문제를 해결해주는 중간 연결자
Bridge(브릿지) 구현과 추상화를 분리하여 독립적으로 변경 가능
Composite(컴포지트) 객체들을 트리 구조로 구성하여 부분-전체 계층 표현
Decorator(데코레이터) 기존 객체에 새로운 기능을 동적으로 추가
Facade(퍼사드) 복잡한 서브시스템을 단순한 인터페이스로 제공
Flyweight(플라이웨이트) 메모리 사용을 줄이기 위해 동일한 객체를 공유
Proxy(프록시) 접근 제어를 위한 대리 객체 제공
행위(Behavioral) 패턴 
- 객체 간 알고리즘이나 책임 분배에 관한 패턴: 여러 객체를 이용해 작업 분배(결합도 최소화 고려해야 함)
Observer(옵저버) 한 객체의 상태 변화가 여러 객체에 전달됨
Strategy(전략) 알고리즘을 캡슐화하고 동적으로 교체 가능
Command(커맨드) 요청을 객체로 캡슐화하여 사용자의 명령을 저장 및 실행
State(상태) 객체의 상태에 따라 행동이 변경되는 패턴
Template Method(템플릿 메서드) 알고리즘의 구조를 정의하고 일부 단계를 서브클래스가 구현
Iterator(이터레이터) 컬렉션의 내부 구조를 공개하지 않고 순회
Mediator(미디에이터) 객체 간 복잡한 상호작용을 캡슐화
Chain of Responsibility(책임 연쇄) 요청을 처리할 객체를 연결하여 책임 분산
Visitor(비지터) 요소에 새로운 기능을 추가하면서 구조 수정 없이 확장 가능
Interpreter(인터프리터) 언어 해석기를 구현하여 문법을 해석

 

5. REST API

  • 가장 대중적으로 많이 사용되는 애플리케이션 인터페이스
    -> 클라이언트는 서버에 접근하고 자원 조작 가능

1) REST (Representational State Transfer)

  • 월드 와이드 웹(WWW)과 같은 분산 하이퍼미디어 시스템 아키텍처의 한 형식
  • 주고받는 자원(resource)에 이름을 붙이고 URI에 명시해,
    HTTP 메서드(GET, POST, PUT, DELETE)로 자원의 상태를 주고받음
  • 주요 특징
무상태성(Stateless) 요청 간에 서버는 클라이언트의 상태를 저장하지 않음 (세션 없음)
캐시 가능성(Cacheable) HTTP 캐시 기능을 적용하여 성능 향상 
유니폼 인터페이스(일관된 인터페이스) URI와 HTTP 메서드의 사용 규칙이 통일됨
-> HTTP 표준 전송 규약을 따르므로, 모든 프로그래밍 언어/플랫폼/기술과 호환
레이어 시스템(Layered System) REST 서버는 네트워크 상 여러 계층으로 구성하여, 구조 확장에 용이
-> 서버 복잡도와는 관계없이, 클라이언트는 서버와 연결되는 포인트만 알면 됨  
클라이언트-서버 아키텍처 REST 서버는 API를 제공하고 클라이언트는 사용자 정보를 관리하는 구조로 설계
-> 클라이언트-서버 간 의존성 낮춤 

2) REST API (Representational State Transfer Application Programming Interface)

  • API: 애플리케이션에서 제공하는 인터페이스로, 서버 또는 프로그램 사이를 연결
  • REST를 기반으로 만든 API를 의미하며, HTTP 프로토콜을 활용해 자원(Resource)에 접근하고 조작
    -> REST 아키텍처를 따르는 시스템/애플리케이션 인터페이스를 의미하는 것!
  • REST 아키텍처를 구현하는 웹서비스를 'RESTful'하다고 표현 

3) REST URI 설계 규칙

(1) 자원(Resource) 중심으로 설계

  • URI는 명사로 표현하며, CRUD는 HTTP 메서드로 분리
  • 예: /users, /products, /posts

(2) 동사 대신 HTTP Method 사용

  • ❌ /getUsers, /createUser
  • ✅ GET /users, POST /users

(3) 복수형 사용 권장

  • ❌ /user, ✅ /users

(4) 계층 구조 표현

  • /users/{userId}/orders → 특정 유저의 주문 목록

(5) 필터링, 정렬은 쿼리 파라미터 사용

  • /products?category=books&sort=price_desc

(6) HTTP 상태 코드 활용

  • 클라이언트가 결과를 명확히 알 수 있도록 적절한 상태 코드 반환

(7) URI 마지막에는 '/'를 사용하지 않고, 리소스의 이름이 길어지면 하이픈(-) 사용

(8) URI는 소문자로 작성하며, 파일의 확장자를 포함하지 않음 

  • HTTP에서 제공하는 Accept 헤더 사용

(9) URL에는 행위(동사)가 아닌 결과(명사)를 작성

  • http://localhost.com/product/123
  • 잘못된 예: http://localhost.com/delete-product/123
  • 행위는 HTTP 메서드로 표현 
반응형