Spring 정리 노트

인자약·2023년 12월 9일
2

Spring

목록 보기
8/9

📕 [Spring Core] Spring Framework 기본

✏️ Chapter 1 - Spring Framework 소개

🧢 Framework이란?

  • 프로그래밍 상에서의 Framework은 기본적으로 프로그래밍을 하기 위한 어떠한 틀이나 구조를 제공한다.

🧢 Framework와 Library의 차이

  • Framework은 개발자가 애플리케이션의 핵심 로직을 개발하는 것에 집중할 수 있도록 해준다.
  • Library는 애플리케이션 흐름의 주도권이 개발자에게 있는 반면, Framework은 애플리케이션 흐름의 주도권이 개발자가 아닌 Framework에 있다.

🧢 Spring Framework이란?

🧢 Spring Framework을 배워야 하는 이유

  • Spring Framework이 도입되기 전에는 JSP나 Servlet 기술을 사용한 Model1, Model2 아키텍처를 기반으로 한 Java 웹 애플리케이션을 제작하였다.
  • Spring MVC 방식이 도입됨으로써 Java 웹 애플리케이션의 제작 방식이 획기적으로 변하게 되었다.
  • Spring MVC 설정의 복잡함과 어려움을 극복하기 위해 Spring Boot이 탄생하게 되었다.

✏️ Chapter 2 - Spring Framework의 특징

🧢 POJO(Plain Old Java Object)

  • POJO란 순수한 Java 객체를 의미한다.
  • POJO 프로그래밍이란 순수 Java 객체가 다른 기술이나 환경에 종속되지 않도록 하기 위한 프로그래밍 기법이다.
  • POJO 프로그래밍을 효과적으로 적용하기 위해서는 특정 기술에 대한 지식보다는 JDK의 API에 대한 지식과 객체지향적인 사고방식과 설계를 위한 훈련이 우선시되어야 한다.
  • Spring Framework은 POJO 프로그래밍을 지향하기 위해 IoC/DI, AOP, PSA라는 기술을 제공한다.

🧢 POJO와 Spring Framework의 관계

  • POJO 프로그래밍을 효과적으로 적용하기 위해서는 특정 기술에 대한 지식보다는 JDK의 API에 대한 지식과 객체지향적인 사고방식과 설계를 위한 훈련이 우선시되어야 한다.
  • Spring Framework은 POJO 프로그래밍을 지향하기 위해 IoC/DI, AOP, PSA라는 기술을 제공한다.

🧢 IoC(Inversion of Control)

  • 애플리케이션 흐름의 주도권이 뒤바뀐 것

🧢 DI(Dependency Injection)

  • 애플리케이션 흐름의 주도권이 사용자에게 있지 않고, Framework이나 서블릿 컨테이너 등 외부에 있는 것 즉, 흐름의 주도권이 뒤바뀐 것을 IoC(Inversion of Control)라고 한다.
  • DI(Dependency Injection)는 IoC 개념을 조금 구체화시킨 것으로 객체 간의 관계를 느슨하게 해 준다.
  • 클래스 내부에서 다른 클래스의 객체를 생성하게 되면 두 클래스 간에 의존 관계가 성립하게 된다.
  • 클래스 내부에서 new를 사용해 참조할 클래스의 객체를 직접 생성하지 않고, 생성자 등을 통해 외부에서 다른 클래스의 객체를 전달받고 있다면 의존성 주입이 이루어지고 있는 것이다.
  • new 키워드를 사용하여 객체를 생성할 때, 클래스 간에 강하게 결합(Tight Coupling)되어 있다고 한다.
  • 어떤 클래스가 인터페이스 같이 일반화된 구성 요소에 의존하고 있을 때, 클래스들 간에 느슨하게 결합(Loose Coupling)되어 있다고 한다.
  • 객체들 간의 느슨한 결합은 요구 사항의 변경에 유연하게 대처할 수 있도록 해 준다.
  • 의존성 주입(DI)은 클래스들 간의 강한 결합을 느슨한 결합으로 만들어준다.
  • Spring에서는 애플리케이션 코드에서 이루어지는 의존성 주입(DI)을 Spring에서 대신해 준다.

🧢 AOP(Aspect Oriented Programming)

🧢 AOP가 필요한 이유

  • AOP(Aspect Oriented Programming)는 관심 지향 프로그래밍이다.
  • AOP에서 의미하는 Aspect는 애플리케이션의 공통 관심사를 의미한다.
  • 애플리케이션의 공통 관심사는 비즈니스 로직을 제외한 애플리케이션 전반에 걸쳐서 사용되는 공통 기능들을 의미한다.
  • 애플리케이션 전반에 걸쳐서 사용되는 공통 기능에는 로깅, 보안, 트랜잭션, 모니터링, 트레이싱 등의 기능이 있다.
  • AOP를 애플리케이션에 적용해서 다음과 같은 이점을 누릴 수 있다.
    1) 코드의 간결성 유지
    2) 객체 지향 설계 원칙에 맞는 코드 구현
    3) 코드의 재사용

🧢 PSA(Portable Service Abstraction)

  • 객체지향 프로그래밍 세계에서 어떤 클래스의 본질적인 특성만을 추출해서 일반화하는 것을 추상화(Abstraction)라고 한다.
  • 클라이언트가 추상화된 상위 클래스를 일관되게 바라보며 하위 클래스의 기능을 사용하는 것이 바로 일관된 서비스 추상화(PSA)의 기본 개념이다.
  • 애플리케이션에서 특정 서비스를 이용할 때, 서비스의 기능을 접근하는 방식 자체를 일관되게 유지하면서 기술 자체를 유연하게 사용할 수 있도록 하는 것을 PSA(일관된 서비스 추상화)라고 한다.
  • PSA가 필요한 주된 이유는 어떤 서비스를 이용하기 위한 접근 방식을 일관된 방식으로 유지함으로써 애플리케이션에서 사용하는 기술이 변경되더라도 최소한의 변경만으로 변경된 요구 사항을 반영하기 위함이다.

✏️ Chapter 3 - Spring Framework 모듈 구성

🧢 아키텍처란?

  • 아키텍처(Architecture)는 건축 분야에서 유래된 용어로써 요구 사항을 만족하는 건축물을 짓는 데 있어 청사진 같은 역할을 한다.
  • 소프트웨어의 구성을 큰 그림으로 표현한 것이 소프트웨어 아키텍처이다.
  • 애플리케이션은 소프트웨어 종류의 하나로서 좁게는 데스크톱이나 스마트폰에서 사용하는 응용 프로그램을 말하며, 넓게는 클라이언트의 요청을 처리하는 서버 애플리케이션을 의미한다.
  • 우리가 중점적으로 알아야 할 아키텍처는 웹 상에서 동작하는 웹 애플리케이션을 위한 아키텍처이다.
  • 애플리케이션의 아키텍처 중에서 우리가 중점적으로 알아야 할 아키텍처는 계층형 애플리케이션 아키텍처이다.
  • REST API 기반 웹 애플리케이션의 계층은 크게 API 계층(API Layer), 비즈니스 계층(Business Layer), 데이터 액세스 계층(Data Access Layer)으로 구분된다.
  • API 계층은 클라이언트의 요청을 받아들이는 계층이다.
  • 비즈니스 계층은 API 계층에서 전달받은 요청을 업무 도메인의 요구 사항에 맞게 비즈니스적으로 처리하는 계층이다.
  • 데이터 액세스 계층은 비즈니스 계층에서 처리된 데이터를 데이터베이스 등의 데이터 저장소에 저장하기 위한 계층이다.

🧢 아키텍처로 보는 Spring Framwork 모듈(Module) 구성

✏️ Chapter 4 - Spring Boot 소개

🧢 Spring Boot이란?

  • Spring Boot은 Spring 설정의 복잡함이라는 문제점을 해결하기 위해 생겨난 Spring Project 중 하나이다.
  • Spring Boot을 사용해야 하는 이유
    1) Spring Boot은 XML 기반의 복잡한 설계 방식을 지양한다.
    2) Spring Boot의 starter 모듈 구성 기능을 통해 의존 라이브러리를 자동으로 구성해 준다.
    3) 애플리케이션 설정의 자동 구성
    4) Spring Boot은 프로덕션급 애플리케이션의 빌드를 손쉽게 할 수 있다.
    5) Spring Boot은 내장된 WAS를 사용가능하기 때문에 배포가 용이하다.
  • Spring Boot의 핵심 콘셉트
    1) Spring 구성은 Spring에게 맡겨버리고 비즈니스 로직에만 집중하자!

📕 [Spring Core] Spring Framework의 핵심 개념

✏️ DI(Dependency Injection)

🧢 스프링 컨테이너와 빈

1) 스프링 컨테이너 생성


2) 빈 조회

  • 스프링 컨테이너가 관리하는 자바 객체를 스프링 빈(Bean)

🧢 스프링 컨테이너 = 싱글톤 컨테이너

🧢 빈 생명주기와 범위

🧢 컴포넌트 스캔과 의존성 자동 주입

  • 자동으로 스프링 빈을 등록하는 컴포넌트 스캔(Component Scan), 더 나아가, 컴포넌트 스캔만으로는 앞에서 우리가 봤던 것과 같은 구체적인 의존 관계 설정이 불가능하기 때문에 @Autowired 애너테이션을 통해 빈을 자동으로 등록함과 동시에 의존 관계가 설정될 수 있도록 편리한 기능을 제공

🧢 @Autowired

1) @Autowired 필드명 매칭
@Autowired는 먼저 타입으로 빈을 조회하고, 만약 2개 이상의 여러 개의 빈이 있는 경우에 필드명 또는 매개변수명으로 빈을 매칭
2) @Qualifier 사용
추가적인 구분자를 통해 의존 관계를 연결하는 방식
3) @Primary 사용
여러 개의 빈이 들어올 수 있는 경우 빈 객체들 간 우선순위를 설정

✏️ AOP(Aspect Oriented Programming)

🧢 AOP와 프록시 객체

  • 스프링 프레임워크가 제공하는 AOP방식은 런타임 시에 프록시(Proxy) 객체를 생성해서 공통 관심 기능을 적용하는 방식을 사용. 영어로 프록시는 “대리”라는 뜻을 가지고 있다. 즉, 어떤 대상의 역할을 대리해서 처리하는 객체라고 이해할 수 있다.

🧢 AOP의 핵심 개념

1) AOP란 공통 관심 사항과 핵심 관심 사항을 분리시켜 코드의 중복을 제거하고, 코드의 재사용성을 높이는 프로그래밍 방법론을 의미한다.
2) AOP은 핵심 기능에 공통기능을 삽입하는 것으로, 이를 통해 핵심 관심 사항 코드의 변경 없이 공통 기능의 구현을 추가 또는 변경하는 것이 가능하다.


📕 [Spring MVC] API 계층

✏️ Chapter - Spring MVC 아키텍처

🧢 Spring MVC란?

  • Spring의 모듈 중에서 서블릿(Servlet) API를 기반으로 클라이언트의 요청을 처리하는 모듈이 바로 spring-webmvc이다.
  • spring-webmvc 모듈이 Spring MVC이다.
  • Spring MVC는 웹 프레임워크의 한 종류이기 때문에 Spring MVC 프레임워크라고도 부른다.
  • Spring MVC에서 M은 Model을 의미한다.
    1) 클라이언트에게 응답으로 돌려주는 작업의 처리 결과 데이터를 Model이라고 한다.
  • Spring MVC에서 V는 View를 의미한다.
    1) View는 Model 데이터를 이용해서 웹브라우저 같은 클라이언트 애플리케이션의 화면에 보이는 리소스(Resource)를 제공한다.
    2) 우리가 실질적으로 학습하게 되는 View는 JSON 포맷의 데이터를 생성한다.
  • Spring MVC에서 C는 Controller를 의미한다.
    1) Controller는 클라이언트 측의 요청을 전달받아 Model과 View의 중간에서 상호 작용을 해주는 역할을 담당한다.
  • Spring MVC에서 MVC의 전체적인 동작 흐름은 다음과 같다.
    1) Client가 요청 데이터 전송 → Controller가 요청 데이터 수신 → 비즈니스 로직 처리 → Model 데이터 생성 → Controller에게 Model 데이터 전달 → Controller가 View에게 Model 데이터 전달 → View가 응답 데이터 생성

🧢 Spring MVC의 동작 방식과 구성 요소

  • Spring MVC의 요청 처리 흐름
    1) 클라이언트의 요청을 제일 먼저 전달받는 구성요소는 DispatcherServlet이다.
    2) DispatcherServlet은 HandlerMapping 인터페이스에게 Controller의 검색을 위임한다.
    3) DispatcherServlet은 검색된 Controller 정보를 토대로 HandlerAdapter 인터페이스에게 Controller 클래스 내에 있는 Handler 메서드의 호출을 위임한다.
    4) HandlerAdapter 인터페이스는 Controller 클래스의 Handler 메서드를 호출한다.
    5) DispatcherServlet은 ViewResolver에게 View의 검색을 위임한다.
    6) DispatcherServlet은 View에게 Model 데이터를 포함한 응답 데이터 생성을 위임한다.
    7) DispatcherServlet은 최종 응답 데이터를 클라이언트에게 전달한다.
  • DispatcherServlet이 애플리케이션의 가장 앞단에 배치되어 다른 구성요소들과 상호작용하면서 클라이언트의 요청을 처리하는 패턴을 Front Controller Pattern이라고 한다.

✏️ Chapter - Controller

🧢 [기본] Controller 클래스 설계 및 구조 생성

  • Spring Boot 애플리케이션으로서 동작하기 위한 엔트리포인트에는 @SpringBootApplication을 추가한다.
  • main() 메서드 내에서 SpringApplication.run()을 호출하면 Spring Boot 기반의 애플리케이션으로 동작한다.
  • @RestController를 클래스에 추가함으로써 해당 클래스를 REST API의 리소스(자원, Resource)를 처리하기 위한 API 엔드포인트로 동작하게 해 준다.
  • @RequestMapping을 Controller 클래스 레벨에 추가하여 클래스 전체에 사용되는 공통 URL(Base URL)을 설정할 수 있다.

🧢 [기본] 핸들러 메서드(Handler Method)

  • 클라이언트의 요청을 전달받아서 처리하기 위해서는 요청 핸들러 메서드(Request Handler Method)가 필요하다.
  • Spring MVC에서는 HTTP Method 유형과 매치되는 @GetMapping, @PostMapping 등의 애너테이션을 지원한다.
  • @PathVariable 애너테이션을 사용하면 클라이언트 요청 URI에 패턴 형식으로 지정된 변수의 값을 파라미터로 전달받을 수 있다.
  • @RequestParam 애너테이션을 사용하면 쿼리 파라미터(Query Parmeter 또는 Query string), 폼 데이터(form-data), x-www-form-urlencoded 형식의 데이터를 파라미터로 전달받을 수 있다.
  • @GetMapping, @PostMapping 등에서 URI를 생략하면 클래스 레벨의 URI 경로만으로 요청 URI를 구성한다.

🧢 [기본] 응답 데이터에 ResponseEntity 적용

  • 핸들러 메서드의 리턴 값으로 Map 객체를 리턴하면 Spring MVC 내부적으로 JSON 형식의 데이터를 생성해 준다. 즉, 클래스 레벨의 @RequestMapping에 ‘produces’ 애트리뷰트를 지정할 필요가 없다.
  • ResponseEntity 클래스로 응답 데이터를 래핑함으로써 조금 더 세련된 방식으로 응답 데이터를 리턴할 수 있다.
  • POST Method 형식의 클라이언트 요청에 대한 응답 상태는 HttpStatus.OK보다는 HttpStatus.CREATED가 조금 더 자연스럽다.

🧢 [심화] HTTP 헤더(Header)

  • HTTP 헤더(Header)는 HTTP 메시지(Messages)의 구성 요소 중 하나로써 클라이언트의 요청이나 서버의 응답에 포함되어 부가적인 정보를 HTTP 메시지에 포함할 수 있다.
  • HTTP Request 헤더(Header) 정보 얻기
    1) @RequestHeader 애너테이션을 이용해서 개별 헤더 정보 및 전체 헤더 정보를 얻을 수 있다.
    2) HttpServletRequest 또는 HttpEntity 객체로 헤더 정보를 얻을 수 있다.
  • HTTP Response 헤더(Header) 정보 추가
    1) ResponseEntity와 HttpHeaders를 이용해 헤더 정보를 추가할 수 있다.
    2) HttpServletResponse 객체를 이용해 헤더 정보를 추가할 수 있다.

🧢 [심화] Rest Client

  • 웹 브라우저는 웹 서버로부터 HTML 콘텐츠를 제공받는 클라이언트 중 하나이다.
  • 어떤 서버가 HTTP 통신을 통해서 다른 서버의 리소스를 이용한다면 그때만큼은 클라이언트의 역할을 한다.
  • Rest Client란 Rest API 서버에 HTTP 요청을 보낼 수 있는 클라이언트 툴 또는 라이브러리를 의미합니다.
  • RestTemplate은 원격지에 있는 다른 Backend 서버에 HTTP 요청을 전송할 수 있는 Rest Client API이다.
  • RestTemplate 사용 단계
    1) RestTemplate 객체를 생성한다.
    2) HTTP 요청을 전송할 엔드포인트의 URI 객체를 생성한다.
    3_ getForObject(), getForEntity(), exchange() 등을 이용해서 HTTP 요청을 전송한다.
  • RestTemplate을 사용할 수 있는 기능 예
    1) 결제 서비스
    2) 카카오톡 등의 메시징 서비스
    3) Google Map 등의 지도 서비스
    4) 공공 데이터 포털, 카카오, 네이버 등에서 제공하는 Open API
    5) 기타 원격지 API 서버와의 통신

✏️ Chapter - DTO(Data Transfer Object)

🧢 [기본] HTTP 요청/응답에서의 DTO(Data Transfer Object)

  • DTO는 Data Transfer Object의 약자로 마틴 파울러(Martin Fowler)가 ‘Patterns of Enterprise Application Architecture’라는 책에서 처음 소개한 엔터프라이즈 애플리케이션 아키텍처 패턴의 하나이다.
  • DTO는 주로 클라이언트에서 서버 쪽으로 전송하는 요청 데이터를 전달받을 때, 서버에서 클라이언트 쪽으로 전송하는 응답 데이터를 전송하기 위한 용도로 사용된다.
  • DTO가 필요한 이유
    1) 클라이언트의 Request Body를 하나의 객체로 모두 전달받을 수 있기 때문에 코드 자체가 간결해진다.
    2) Request Body의 데이터 유효성(Validation) 검증이 단순해진다.
  • JSON 형식의 Request Body를 전달받기 위해서는 DTO 객체에 @RequestBody 애너테이션을 붙여야 한다.
  • Response Body를 JSON 형식으로 전달하기 위해서는 @ResponseBody 애너테이션을 메서드 앞에 붙여 주어야 하지만 ResponseEntity 객체를 리턴 값으로 사용할 경우 @ResponseBody를 생략할 수 있다.
  • 클라이언트 쪽에서 JSON 형식의 데이터를 서버 쪽으로 전송하면 서버 쪽의 웹 애플리케이션은 전달받은 JSON 형식의 데이터를 DTO 같은 Java의 객체로 변환하는데 이를 역직렬화(Deserialization)이라고 한다.
  • 서버 쪽에서 클라이언트에게 응답 데이터를 전송하기 위해서 DTO 같은 Java의 객체를 JSON 형식으로 변환하는 것을 직렬화(Serialization)라고 한다.

🧢 [기본] DTO 유효성 검증(Validation)

  • 프론트엔드 쪽에서 유효성 검증을 진행했다 하더라도 서버 쪽에서 추가적으로 유효성 검증을 반드시 진행해야 한다.
  • 프론트엔드 쪽에서의 유효성 검증 프로세스는 사용자 편의성 측면에서 필요한 작업이다.
  • Jakarta Bean Validation의 애너테이션을 이용하면 Controller 로직에서 유효성 검증 로직을 분리할 수 있다.
  • Jakarta Bean Validation은 애너테이션 기반 유효성 검증을 위한 표준 스펙이다.
  • Hibernate Validator는 Jakarta Bean Validation 스펙을 구현한 구현체이다.
  • Spring에서 지원하는 @Validated 애너테이션을 사용하면 쿼리 파라미터(Query Parameter 또는 Query String) 및 @Pathvariable에 대한 유효성 검증을 진행할 수 있다.
  • Jakarta Bean Validation에서 빌트인(Built-in)으로 지원하지 않는 애너테이션은 Custom Validator를 통해 Custom Annotation을 구현한 후, 적용할 수 있다.

📕[Spring MVC]서비스 계층

✏️ 서비스 계층에서의 DI

🧢 [기본] DI를 통한 서비스 계층 ↔ API 계층 연동

  • 애플리케이션에 있어 Service는 도메인 업무 영역을 구현하는 비즈니스 로직을 처리하는 것을 의미한다.
  • Controller 클래스에 @RestController 애너테이션을 추가하면 Spring Bean으로 등록된다.
  • Service 클래스에 @Service 애너테이션을 추가하면 Spring Bean으로 등록된다.
  • 생성자 방식의 DI는 생성자가 하나일 경우에는 @Autowired 애너테이션을 추가하지 않아도 DI가 적용된다.

🧢 [기본] 매퍼(Mapper)를 이용한 DTO 클래스 ↔ 엔티티(Entity) 클래스 매핑

  • Mapper를 사용해서 DTO 클래스와 Entity 클래스 간의 관심사를 분리할 수 있다.
  • Mapper를 개발자가 직접 구현하기보다는 MapStruct 같은 매핑 라이브러리를 사용하는 것이 생산성 측면에서 더 나은 선택이다.

📕 [Spring MVC] 예외 처리

✏️ Chapter - Spring MVC에서의 예외 처리

🧢 [기본] @ExceptionHandler를 이용한 예외 처리

  • Controller 클래스 레벨에서 @ExceptionHandler 애너테이션을 사용하면 해당 Controller에서 발생하는 예외를 처리할 수 있다.
  • 필요한 Error 정보만 담을 수 있는 Error 전용 Response 객체를 사용하면 클라이언트에게 조금 더 친절한 에러 정보를 제공할 수 있다.
  • @ExceptionHandler 애너테이션 방식은 Controller마다 동일하게 발생하는 예외 처리에 대한 중복 코드가 발생할 수 있다.
  • @ExceptionHandler 애너테이션 방식은 다양한 유형의 예외를 처리하기에는 적절하지 않은 방식이다.

🧢 [기본] @RestControllerAdvice를 이용한 예외처리

  • @RestControllerAdvice 애너테이션을 추가한 클래스를 이용하면 예외 처리를 공통화할 수 있다.
  • @RestControllerAdvice 애너테이션을 사용하면 JSON 형식의 데이터를 Response Body로 전송하기 위해 ResponseEntity로 래핑 할 필요가 없다.
  • @ResponseStatus 애너테이션으로 HTTP Status를 대신 표현할 수 있다.

✏️ Chapter - 비즈니스 로직에대한 예외 처리

🧢 비즈니스적인 예외 던지기(throw) 및 예외 처리

  • 체크 예외(Checked Exception)는 예외를 잡아서(catch) 체크한 후에 해당 예외를 복구하든가 아니면 회피를 하든가 등의 어떤 구체적인 처리를 해야 하는 예외이다.
  • 언체크 예외(Unchecked Exception)는 예외를 잡아서(catch) 해당 예외에 대한 어떤 처리를 할 필요가 없는 예외를 의미한다.
  • RuntimeException을 상속한 예외는 모두 언체크 예외(Unchked Exception)이다.
  • RuntimeException을 상속해서 개발자가 직접 사용자 정의 예외(Custom Exception)를 만들 수 있다.
  • 사용자 정의 예외(Custom Exception)를 정의해서 서비스 계층의 비즈니스 로직에서 발생하는 다양한 예외를 던질 수 있고, 던져진 예외는 Exception Advice에서 처리할 수 있다.
  • @ResponseStatus 애너테이션은 고정된 예외를 처리할 경우에 사용할 수 있다.
  • HttpStatus가 동적으로 변경되는 경우에는 ResponseEntity를 사용한다.

📕 [Spring MVC] JPA 기반 데이터 엑세스 계층

✏️ Chapter - Hello, Spring Data JPA

🧢 JDBC란?

  • JDBC(Java Database Connectivity)는 Java 기반 애플리케이션의 코드 레벨에서 사용하는 데이터를 데이터베이스에 저장 및 업데이트하거나 반대로 데이터베이스에 저장된 데이터를 Java 코드 레벨에서 사용할 수 있도록 해주는 Java에서 제공하는 표준 API이다.
  • JDBC의 구체적인 API 사용법을 알 필요는 없지만 JDBC의 동작 흐름을 알면 Spring에서 지원하는 데이터 액세스 기술을 사용하는데 도움이 된다.
  • 데이터베이스 Connection 객체를 미리 만들어서 보관하고 애플리케이션이 필요할 때 이 Connection을 제공해 주는 역할을 하는 Connection 관리자를 바로 Connection Pool이라고 한다.
  • Spring Boot 2.0부터 HikariCP가 기본 DBCP로 채택되었다.

🧢 [기본] Spring Data JPA란?

  • Spring Data JPA는 JPA 스펙을 구현한 구현체의 API를 조금 더 쉽게 사용할 수 있도록 해주는 모듈이다.
  • Spring Data는 PSA(Portable Service Abstraction)가 적용되어 있어 Repository와 엔티티 객체 맵핑 추상화, Repository에 정의된 메서드를 이용한 동적 쿼리 생성 등의 기능을 제공한다. 이를 통해 개발자는 데이터 접근 기술을 보다 쉽게 활용할 수 있다.

🧢 [기본] Hello Spring Data JPA로 이해하는 Spring Data JPA (1)

  • 데이터 액세스 기술의 유형은 크게 SQL 중심의 기술과 객체(Object) 중심의 기술로 나눌 수 있다.
  • SQL 중심의 기술에는 mybatis, Spring JDBC 등이 있다.
  • 객체(Object) 중심의 기술에는 JPA, Spring Data JDBC 등이 있다.
  • JPA 같은 객체(Object) 중심의 기술을 ORM(Object-Relational Mapping) 기술이라고 한다.
  • 인메모리(In-memory) DB는 애플리케이션이 실행된 상태에서만 데이터를 저장하고 애플리케이션 실행이 중지되면 인메모리 DB 역시 실행이 중지되어 저장된 데이터가 사라진다.

🧢 [기본] Hello Spring Data JPA로 이해하는 Spring Data JPA (2)

  • Spring에서 지원하는 JpaRepository 인터페이스는 CRUD에 대한 기본적인 메서드를 정의하고 있기 때문에 별도의 CRUD 기능을 개발자가 직접 구현할 필요가 없다.
  • application.properties 또는 application.yml 파일의 설정 정보 등록을 통해 데이터베이스 설정, 데이터베이스의 초기화 설정 등의 다양한 설정을 할 수 있다.
  • application.yml 방식은 중복되는 프로퍼티의 입력을 줄여주기 때문에 application.properties 방식보다 더 선호되는 추세이다.
  • 엔티티(Entity) 클래스에 @Entity 애너테이션을 추가하면 같은 이름의 데이터베이스 테이블에 매핑되고, 엔티티 클래스 각각의 멤버 변수는 데이터베이스 테이블의 컬럼(Column)에 매핑된다.
  • 엔티티 클래스의 멤버 변수에 @Id 애너테이션을 추가하면 데이터베이스 테이블의 기본키(Primary key) 열과 매핑된다.

✏️ Chapter - JPA(Java Persistence API) 개요

🧢 JPA(Java Persistence API)란?

  • JPA(Java Persistence API)는 Java 진영에서 사용하는 ORM(Object-Relational Mapping) 기술의 표준 사양(또는 명세, Specification)이다.
  • Hibernate ORM은 JPA에서 정의해 둔 인터페이스를 구현한 구현체로써 JPA에서 지원하는 기능 이외에 Hibernate 자체적으로 사용할 수 있는 API 역시 지원하고 있다.
  • JPA에서는 테이블과 매핑되는 엔티티 객체 정보를 영속성 컨텍스트(Persistence Context)에 보관해서 애플리케이션 내에서 오래 지속되도록 한다.
  • 영속성 컨텍스트 관련 JPA API
    1) em.persist()를 사용해서 엔티티 객체를 영속성 컨텍스트에 저장할 수 있다.
    2) 엔티티 객체의 setter 메서드를 사용해서 영속성 컨텍스트에 저장된 엔티티 객체의 정보를 업데이트할 수 있다.
    3) em.remove()를 사용해서 엔티티 객체를 영속성 컨텍스트에서 제거할 수 있다.
    4) em.flush()를 사용해서 영속성 컨텍스트의 변경 사항을 테이블에 반영할 수 있다.
    5) tx.commit()을 호출하면 내부적으로 em.flush()가 호출된다.

✏️ Chapter - JPA 엔티티(Entity) 매핑과 연관 관계 매핑

🧢 [기본] 엔티티 매핑

  • @Entity 애너테이션을 클래스 레벨에 추가하면 JPA의 관리대상 엔티티가 된다.
  • @Table 애너테이션은 엔티티와 매핑할 테이블을 지정한다.
  • @Entity 애너테이션과 @Id 애너테이션은 필수로 추가해야 한다.
  • JPA는 IDENTITY, SEQUENCE, TABLE, AUTO 전략 같은 다양한 기본키 생성 전략을 지원한다.
    1) IDENTITY 전략
    기본키 생성을 데이터베이스에 위임하는 전략이다.
    2) SEQUENCE 전략
    데이터베이스에서 제공하는 시퀀스를 사용해서 기본키를 생성하는 전략이다.
    3) TABLE 전략
    별도의 키 생성 테이블을 사용하는 전략이다.
    4) AUTO 전략
    JPA가 데이터베이스의 Dialect에 따라서 적절한 전략을 자동으로 선택한다.
  • Java의 원시 타입 필드에서 @Column 애너테이션이 없거나 @Column 애너테이션이 있지만 애트리뷰트를 생략한 경우, 최소한 nullable=false는 설정하는 것이 에러를 미연에 방지하는 길이다.
  • java.util.Date, java.util.Calendar 타입으로 매핑하기 위해서는 @Temporal 애너테이션을 추가해야 하지만 LocalDate, LocalDateTime 타입일 경우, @Temporal 애너테이션은 생략 가능하다.
  • @Transient 애너테이션을 필드에 추가하면 JPA가 테이블 열과 매핑하지 않겠다는 의미로 인식한다.
  • 테이블에 이미 저장되어 있는 enum 순서 번호와 enum에 정의되어 있는 순서가 일치하지 않게 되는 문제가 발생하지 않도록 EnumType.STRING을 사용하는 것이 좋다.

🧢 [기본] 엔티티 간의 연관 관계 매핑

  • JPA는 엔티티 간에 단방향과 양방향 매핑을 모두 지원한다.
  • JPA는 엔티티 간에 일대다, 다대일, 다대다, 일대일 연관 관계 매핑을 지원한다.
  • 일대다 관계는 외래키를 가지고 있어야 할 엔티티에 외래키 역할을 하는 객체 참조가 없기 때문에 가급적 사용하지 않는 것이 좋다.
  • 다대일 매핑(@ManyToOne)은 다대일에서 ‘다’에 해당하는 엔티티에서 사용한다.
    1) @JoinColumn 애너테이션은 다대일 매핑(@ManyToOne)에 사용한다.
    2) @JoinColumn 애너테이션의 name 애트리뷰트 값에는 테이블 조인 시 사용되는 외래키가 저장되는 열 이름을 지정한다.
  • 일대다(@OneToMany) 양방향 매핑은 다대일에서 ‘일’에 해당하는 엔티티에서 사용한다.
    1) @OneToMany의 mappedBy 애트리뷰트의 값으로 외래키 역할을 하는 객체의 필드이름을 지정한다.
  • 다대다 연관 관계 매핑은 두 개의 다대일 단방향 매핑을 적용하고, 필요한 경우 양방향 매핑을 적용한다.
  • 일대일 연관 관계 매핑 방식은 @OneToOne 애너테이션을 사용한다는 것 외에 @ManyToOne 단방향 방식, 양방향 방식과 동일하다.

✏️ Chapter - Spring Data JPA

🧢 [기본] Spring Data JPA를 통한 데이터 액세스 계층 구현

  • Spring Data JPA는 Spring Data 패밀리 기술 중 하나로써, JPA 기반의 데이터 액세스 기술을 좀 더 쉽게 사용할 수 있게 해 준다.
  • JPA는 엔터프라이즈 Java 애플리케이션에서 관계형 데이터베이스를 사용하기 위해 정해 놓은 표준 스펙(사양 또는 명세, Specification)이다.
  • Hibernate ORM은 JPA라는 표준 스펙을 구현한 구현체이다.
  • Spring Data JPA는 JPA 스펙을 구현한 구현체의 API(일반적으로 Hibernate ORM)를 조금 더 쉽게 사용할 수 있도록 해주는 모듈이다.
  • Spring에서는 애플리케이션이 특정 기술에 강하게 결합되지 않도록 Spring이 추구하는 PSA(일관된 서비스 추상화)를 통해 개발자는 일관된 코드 구현 방식을 유지하도록 하고, 기술의 변경이 필요할 때 최소한의 변경만을 하도록 지원한다.
  • JpaRepository를 상속하면 CrudRepository 기능을 포함한 JPA에 특화된 확장 기능들을 사용할 수 있다.
  • JPQL은 JPA에서 지원하는 객체 지향 쿼리로써 데이터베이스의 테이블을 대상으로 조회 작업을 진행하는 것이 아니라 엔티티 클래스의 객체를 대상으로 객체를 조회한다.
  • JPQL의 문법을 사용해서 객체를 조회하면 JPA가 내부적으로 JPQL을 분석해서 적절한 SQL을 만든 후에 데이터베이스를 조회하고, 조회한 결과를 엔티티 객체로 매핑한 뒤에 반환한다.

📕 [Spring MVC] 트랜잭션(Transaction)

✏️ Chapter - 트랜잭션 개요

🧢 [기본] 트랜잭션(Transaction)이란?

  • 트랜잭션은 여러 개의 작업들을 하나의 그룹으로 묶어서 처리하는 처리 단위를 의미 한다.
  • ACID 원칙
    1) 원자성(Atomicity)
    트랜잭션에서의 원자성(Atomicity)이란 작업을 더 이상 쪼갤 수 없음을 의미 한다.
    따라서 논리적으로 하나의 작업으로 인식해서 둘 다 성공하든 둘 다 실패하든가(All or Nothing)의 둘 중 하나로만 처리되는 것이 보장된다.
    2) 일관성(Consistency)
    일관성(Consistency)은 트랜잭션이 에러 없이 성공적으로 종료될 경우, 비즈니스 로직에서 의도하는 대로 일관성 있게 저장되거나 변경되는 것을 의미 한다.
    3) 고립성(Isolation)
    고립성(Isolation)은 여러 개의 트랜잭션이 실행될 경우 각각 독립적으로 실행이 되어야 함을 의미 한다.
    4) 지속성(Durability)
    지속성(Durability)은 여러분들이 잘 알고 있다시피 데이터베이스가 종료되어도 데이터는 물리적인 저장소에 저장되어 지속적으로 유지되어야 한다는 의미 한다.
  • 커밋(commit)
    1) 커밋(commit)은 모든 작업을 최종적으로 데이터베이스에 반영하는 명령어로써 commit 명령을 수행하면 변경된 내용이 데이터베이스에 영구적으로 저장된다.
    2) 만약 commit 명령을 수행하지 않으면 작업의 결과가 데이터베이스에 최종적으로 반영되지 않는다.
    3) commit 명령을 수행하면, 하나의 트랜젝션 과정은 종료하게 된다.
  • 롤백(rollback)
    1) 롤백(rollback)은 작업 중 문제가 발생했을 때, 트랜잭션 내에서 수행된 작업들을 취소한다.
    2) 따라서 트랜잭션 시작 이 전의 상태로 되돌아간다.
  • JPA 기술을 사용한 데이터베이스와의 인터랙션은 내부적으로는 JDBC API를 통해서 이루어진다.

✏️ Chapter - Spring Framework에서의 트랜잭션 처리

🧢 [기본] 선언형 방식의 트랜잭션 적용

  • 트랜잭션 관련 설정은 Spring Boot이 내부적으로 알아서 해주기 때문에 개발자가 직접적으로 트랜잭션 설정해 줄 필요가 없다.
  • Spring에서는 일반적으로 애너테이션 방식( @Transactional )의 트랜잭션과 AOP 방식의 트랜잭션 적용 방식을 사용한다.
  • 체크 예외(checked exception)는 @Transactional 애너테이션만 추가해서는 rollback이 되지 않으며, @Transactional(rollbackFor = {SQLException.class, DataFormatException.class})와 같이 해당 체크 예외를 직접 지정해 주거나 언체크 예외(unchecked exception)로 감싸야 rollback 기능을 적용할 수 있다.
  • 트랜잭션 전파란 트랜잭션의 경계에서 진행 중인 트랜잭션이 존재할 때 또는 존재하지 않을 때, 어떻게 동작할 것인지 결정하는 방식을 의미한다.
  • @Transactional 애너테이션의 isolation 애트리뷰트를 통해 트랜잭션 격리 레벨을 지정할 수 있다.

📕 [Spring MVC] 테스팅(Testing)

✏️ Chapter - 단위 테스트(Unit Test)

🧢 단위 테스트란?

  • 테스트란 어떤 대상에 대한 일정 기준을 정해놓고, 그 대상이 정해진 기준에 부합하는지 부합하지 못하는지를 검증하는 과정이다.
  • 우리가 IntelliJ IDE에서 애플리케이션을 실행한 후에 애플리케이션에 Postman으로 HTTP 요청을 전송해서 기대했던 JSON 응답 결과를 확인하는 것 역시 테스트이다.
  • 기능 테스트는 주로 애플리케이션을 사용하는 사용자 입장에서 애플리케이션이 제공하는 기능이 올바르게 동작하는지 테스트하는 것을 의미한다.
  • 통합 테스트는 클라이언트 측 툴 없이 개발자가 짜 놓은 테스트 코드를 실행시켜서 이루어지는 경우가 많다.
  • 슬라이스 테스트는 애플리케이션을 특정 계층으로 쪼개어서 하는 테스트를 의미한다.
  • 일반적으로 단위 테스트는 메서드 단위로 작성된다.
  • 테스트 케이스란 테스트를 위한 입력 데이터, 실행 조건, 기대 결과를 표현하기 위한 명세를 의미한다.
  • 단위 테스트를 위한 F.I.R.S.T 원칙
    1) Fast(빠르게)
    2) Independent(독립적으로)
    3) Repeatable(반복 가능하도록)
    4) Self-validating(셀프 검증이 되도록)
    5) Timely(시기적절하게)
  • Given-When-Then 표현 스타일
    1) Given
    테스트를 위한 준비 과정을 명시한다.
    2) When
    테스트할 동작(대상)을 지정한다.
    3) Then
    테스트의 결과를 검증(Assertion)한다.
  • Assertion(어써션)은 ‘예상하는 결과 값이 참(true)이길 바라는 것’을 의미한다.

✏️ Chapter - JUnit을 사용한 단위 테스트

🧢 [기본] JUnit으로 비즈니스 로직에 단위 테스트 적용하기

  • JUnit은 Java 언어로 만들어진 애플리케이션을 테스트하기 위한 오픈 소스 테스트 프레임워크이다.
  • JUnit은 2022년 현재 Junit 5가 릴리스 되어 있다.
  • JUnit으로 테스트 케이스를 작성하기 위해서는 기본적으로 @Test 애너테이션을 추가해야 한다.
  • JUnit은 assertXXXX()로 시작하는 다양한 Assertion 메서드를 지원한다.
  • JUnit은 테스트 케이스 실행 전, 후에 어떤 처리 로직을 작성할 수 있도록 @BeforeEach, @BeforeAll, @AfterEach, @AfterAll 등의 애너테이션을 지원한다.

✏️ Chapter - Hamcrest를 사용한 Assertion

🧢 [기본] Hamcrest란?

  • Hamcrest는 JUnit 기반의 단위 테스트에서 사용할 수 있는 Assertion Framework이다.
  • Hamcrest는 다음과 같은 이유로 JUnit에 지원하는 Assertion 메서드 보다 더 많이 사용된다.
    1) Assertion을 위한 매쳐(Matcher)가 자연스러운 문장으로 이어지므로 가독성이 향상된다.
    2) 테스트 실패 메시지를 이해하기 쉽다.
    3) 다양한 Matcher를 제공한다.
  • Hamcrest 만으로 던져진(thrown) 예외를 테스트하기 위해서는 Custom Matcher를 직접 구현해서 사용할 수 있다.

✏️ Chapter - 슬라이스 테스트(Slice Test)

🧢 [기본] API 계층 테스트

  • 개발자가 각 계층에 구현해 놓은 기능들이 잘 동작하는지 특정 계층만 잘라서(Slice) 테스트하는 것을 슬라이스 테스트(Slice Test)라고 한다.
  • @SpringBootTest 애너테이션은 Spring Boot 기반의 애플리케이션을 테스트하기 위한 Application Context를 생성한다.
  • @AutoConfigureMockMvc 애너테이션은 Controller 테스트를 위한 애플리케이션의 자동 구성 작업을 해준다.
  • MockMvc는 Tomcat 같은 서버를 실행하지 않고 Spring 기반 애플리케이션의 Controller를 테스트할 수 있는 완벽한 환경을 지원해 주는 일종의 Spring MVC 테스트 프레임워크이다.
  • MockMvc로 테스트 대상 Controller의 핸들러 메서드에 요청을 전송하기 위해서는 기본적으로 perform() 메서드를 먼저 호출해야 한다.
  • MockMvcRequestBuilders 클래스를 이용해서 빌더 패턴을 통해 request 정보를 채워 넣을 수 있다.
  • MockMvc의 perform() 메서드가 리턴하는 ResultActions 타입의 객체를 이용해서 request에 대한 검증을 수행할 수 있다.

🧢 [기본] 데이터 액세스 계층 테스트

  • 데이터 액세스 계층 테스트 시에는 테스트 종료 직 후, DB의 상태를 테스트 케이스 실행 이전으로 되돌려서 깨끗하게 만든다.
  • @DataJpaTest 애너테이션을 사용하면 Spring Data JPA 환경에서 데이터 액세스 계층의 테스트를 손쉽게 진행할 수 있다.
  • @DataJpaTest 애너테이션은 @Transactional 애너테이션을 포함하고 있기 때문에 하나의 테스트 케이스 실행이 종료되는 시점에 데이터베이스에 저장된 데이터는 rollback 처리된다.

✏️ Chapter - Mockito

🧢 [기본] Mockito란?

  • 테스트 세계에서의 Mock은 바로 가짜 객체를 의미한다.
  • Mockito는 Mock 객체를 생성하고, 해당 Mock 객체가 진짜처럼 동작하게 하는 기능을 하는 Mocking framework(또는 라이브러리)이다.
  • @MockBean 애너테이션은 Application Context에 등록되어 있는 Bean에 대한 Mockito Mock 객체를 생성하고 주입해 주는 역할을 한다.
  • Junit에서 Spring을 사용하지 않고 순수하게 Mockito의 기능만을 사용하기 위해서는 @ExtendWith(MockitoExtension.class)를 클래스 레벨에 추가해야 한다.
  • @Mock 애너테이션을 추가하면 해당 필드의 객체를 Mock 객체로 생성한다.
  • @Mcok 애너테이션을 통해 생성된 Mock 객체는 @InjectMocks 애너테이션을 추가한 필드에 주입된다.

📕 [Spring MVC] API 문서화

✏️ Chapter - API 문서화

🧢 API 문서화(Documentation)가 필요한 이유

  • API 문서화란 클라이언트가 REST API 백엔드 애플리케이션에 요청을 전송하기 위해서 알아야 되는 요청 정보(요청 URL(또는 URI), request body, query parameter 등)를 문서로 잘 정리하는 것을 의미한다.
  • API 사용을 위한 어떤 정보가 담겨 있는 문서를 API 문서 또는 API 스펙(사양, Specification)이라고 한다.
  • API 문서 생성의 자동화가 필요한 이유
    1) API 문서를 수기로 직접 작성하는 것은 너무 비효율적이다.
    2) API 문서에 기능이 추가되거나 수정되면 API 문서 역시 함께 수정되어야 하는데, API 문서를 수기로 작성하면 API 문서에 추가된 기능을 빠뜨릴 수도 있고, 클라이언트에게 제공된 API 정보와 수기로 작성한 API 문서의 정보가 다를 수도 있다.
  • Swagger의 API 문서화 방식
    1) 애터네이션 기반의 API 문서화 방식
    2) 애플리케이션 코드에 문서화를 위한 애너테이션들이 포함된다.
    3) 가독성 및 유지 보수성이 떨어진다.
    4) API 문서와 API 코드 간의 정보 불일치 문제가 발생할 수 있다.
    5) API 툴로써의 기능을 활용할 수 있다.
  • Spring Rest Docs의 API 문서화 방식
    1) 테스트 코드 기반의 API 문서화 방식
    2) 애플리케이션 코드에 문서화를 위한 정보들이 포함되지 않는다.
    3) 테스트 케이스의 실행이 “passed”여야 API 문서가 생성된다.
    4) 테스트 케이스를 반드시 작성해야 된다.
    5) API 툴로써의 기능은 제공하지 않는다.

✏️ Chapter - Spring Rest Docs

🧢 Spring Rest Docs란?

  • Spring Rest Docs의 API 문서 생성 흐름은 다음과 같습니다.
    1) 슬라이스 테스트 코드 작성 →
    2) API 스펙 정보 코드 작성 →
    3) test 태스크 실행 →
    4) API 문서 스니펫 생성
    5) 스니펫을 포함한 API 문서 생성
    6) .adoc 파일의 API 문서를 HTML로 변환
  • Spring Rest Docs를 사용해서 API 문서를 생성하기 위해서는 .adoc 문서 스니펫을 생성해 주는 Asciidoctor가 필요하다.
  • HTML 파일로 변환된 API 문서는 외부에 제공할 수도 있고, 웹브라우저에 접속해서 API 문서를 확인할 수도 있다.

🧢 Controller 테스트 케이스에 Spring RestDocs 적용하기

  • @SpringBootTest는 데이터베이스까지 요청 프로세스가 이어지는 통합 테스트에 주로 사용되고, @WebMvcTest는 Controller를 위한 슬라이스 테스트에 주로 사용한다.

  • document(…) 메서드는 API 스펙 정보를 전달받아서 실질적인 문서화 작업을 수행하는 RestDocumentationResultHandler 클래스에서 가장 핵심 기능을 하는 메서드이다.

  • OperationRequestPreprocessor와 OperationResponsePreprocessor를 이용해 API 문서를 생성 전에 전처리를 수행할 수 있다.

  • requestFields(…)는 문서로 표현될 request body를 의미하며, 파라미터로 전달되는 List의 원소인 FieldDescriptor 객체가 request body에 포함되는 데이터를 표현한다.

  • responseFields(…)는 문서로 표현될 response body를 의미하며, 파라미터로 전달되는 List의 원소인 FieldDescriptor 객체가 response body에 포함된 데이터를 표현한다.

🧢 스니펫을 이용한 API 문서화

  • Controller 테스트를 위한 테스트 케이스 실행으로 생성된 API 문서 스니펫은 템플릿 문서에 포함해서 사용할 수 있다.

  • 애플리케이션 빌드를 통해 템플릿 문서를 HTML 파일로 변환할 수 있다.

  • 변환된 HTML 파일을 ‘src/main/resources/static/docs/’ 디렉토리에 위치시키면 웹 브라우저로 API 문서를 확인할 수 있다.

🧢 Spring Rest Docs에서의 Asciidoc

  • Asciidoc은 Spring Rest Docs를 통해 생성되는 텍스트 기반 문서 포맷이다.

  • Asciidoc은 주로 기술 문서 작성을 위해 설계된 가벼운 마크업 언어이기도 하다.

  • Asciidoc을 이용해서 조금 더 세련되고, 가독성 좋은 API 문서를 만들 수 있다.

  • Asciidoctor는 AsciiDoc 포맷의 문서를 파싱 해서 HTML 5, 매뉴얼 페이지, PDF 및 EPUB 3 등의 문서를 생성하는 툴이다.

📕 [Spring MVC] 애플리케이션 빌드 / 실행 / 배포

✏️ Spring 애플리케이션 빌드/실행/배포

🧢 [기본] 애플리케이션 빌드/실행/배포

  • Spring Boot 기반 애플리케이션을 가장 손쉽게 빌드할 수 있는 방법은 IntelliJ 같은 IDE의 기능을 활용하는 것이다.

  • IDE 등의 기능을 활용하기 어려운 상황에서는 Gradle 명령어를 사용해 손쉽게 빌드할 수 있다.

  • Spring에서는 프로파일 기능을 이용해서 빌드 후 생성되는 애플리케이션 실행 파일에 대한 실행 환경을 손쉽게 지정할 수 있다.

  • Spring Boot 기반의 Executable Jar 파일은 전통적인 서버, 클라우드 환경, 가상화 환경에 손쉽게 배포할 수 있다.

    📕 [Spring Security]Spring security 기본

✏️ Chapter - Spring Security 개요

🧢 Spring Security란?

  • Spring Security는 Spring MVC 기반 애플리케이션의 인증(Authentication)과 인가(Authorization or 권한 부여) 기능을 지원하는 보안 프레임워크로써, Spring MVC 기반 애플리케이션에 보안을 적용하기 위한 사실상의 표준이다.

  • Principal(주체)은 일반적으로 인증 프로세스가 성공적으로 수행된 사용자의 계정 정보를 의미한다.

  • Authentication(인증)은 애플리케이션을 사용하는 사용자가 본인이 맞음을 증명하는 절차를 의미한다.

  • Authorization(인가 또는 권한 부여)은 Authentication이 정상적으로 수행된 사용자에게 하나 이상의 권한(authority)을 부여하여 특정 애플리케이션의 특정 리소스에 접근할 수 있게 허가하는 과정을 의미한다.

  • Credential(신원 증명 정보)은 Authentication을 정상적으로 수행하기 위해서는 사용자를 식별하기 위한 정보를 의미한다.

  • Access Control(접근 제어)은 사용자가 애플리케이션의 리소스에 접근하는 행위를 제어하는 것을 의미한다.

🧢 Spring Security를 사용해야 하는 이유

  • 보안 기능을 밑바닥부터 직접 구현하는 것보다 잘 검증되어 신뢰할 만한 Spring Security를 사용하는 것이 더 나은 선택이다.

  • Spring Security는 특정 보안 요구 사항을 만족하기 위한 커스터마이징이 용이하고, 유연한 확장이 가능하다.

🧢 [기본] Hello, Spring Security로 알아보는 Spring Security의 기본 구조 (1)

  • Spring Security의 기본 구조와 기본적인 동작 방식을 이해하기 가장 좋은 인증 방식은 폼 로그인 인증 방식이다.

  • Spring Security를 이용한 보안 설정은 HttpSecurity를 파라미터로 가지고, SecurityFilterChain을 리턴하는 Bean을 생성하면 된다.

  • HttpSecurity를 통해 Spring Security에서 지원하는 보안 설정을 구성할 수 있다.

  • 로컬 환경에서 Spring Security를 테스트하기 위해서는 CSRF 설정을 비활성화해야 한다.

  • InMemoryUserDetailsManager를 이용해 데이터베이스 연동 없이 테스트 목적의 InMemory User를 생성할 수 있다.

🧢 [기본] Hello, Spring Security로 알아보는 Spring Security의 기본 구조 (2)

  • Spring Security에서 지원하는 InMemory User는 말 그대로 메모리에 등록되어 사용되는 User이므로 애플리케이션 실행이 종료되면 InMember User 역시 메모리에서 사라진다.

  • InMemory User를 사용하는 방식은 테스트 환경이나 데모 환경에서 사용할 수 있는 방법이다.

  • Spring Security는 사용자의 크리덴셜(Credential, 자격증명을 위한 구체적인 수단)을 암호화하기 위한 PasswordEncoder를 제공하며, PasswordEncoder는 다양한 암호화 방식을 제공하며, Spring Security에서 지원하는 PasswordEncoder의 디폴트 암호화 알고리즘은 bcrypt이다.

  • 패스워드 같은 민감한(sensitive) 정보는 반드시 암호화되어 저장되어야 합니다.
    패스워드는 복호화할 이유가 없으므로 단방향 암호화 방식으로 암호화되어야 한다.

  • Spring Security에서 SimpleGrantedAuthority를 사용해 Role 베이스 형태의 권한을 지정할 때 ‘ROLE_’ + 권한명 형태로 지정해 주어야 한다.

  • Spring Security에서는 Spring Security에서 관리하는 User 정보를 UserDetails로 관리한다.

  • UserDetails는 UserDetailsService에 의해 로드(load)되는 핵심 User 정보를 표현하는 인터페이스입니다.

  • UserDetailsService는 User 정보를 로드(load)하는 핵심 인터페이스이다.

  • 일반적으로 Spring Security에서는 인증을 시도하는 주체를 User(비슷한 의미로 Principal도 있음)라고 부른다. Principal은 User의 더 구체적인 정보를 의미하며, 일반적으로 Username을 의미한다.

  • Custom UserDetailsService를 사용해 로그인 인증을 처리하는 방식은 Spring Security가 내부적으로 인증을 대신 처리해 주는 방식이다.

  • AuthenticationProvider는 Spring Security에서 클라이언트로부터 전달받은 인증 정보를 바탕으로 인증된 사용자인지를 처리하는 Spring Security의 컴포넌트이다.

🧢 [기본] Spring Security의 웹 요청 처리 흐름

  • Spring Security를 애플리케이션에 적용하는 데 어려움을 겪는 큰 이유 중에 하나는 Spring Security의 아키텍처와 Spring Security의 컴포넌트들이 어떻게 인터랙션 해서 인증, 권한 등의 보안 작업을 처리하는지 이해하지 못하기 때문이다.

  • 서블릿 필터(Servlet Filter)는 서블릿 기반 애플리케이션의 엔드포인트에 요청이 도달하기 전에 중간에서 요청을 가로챈 후 어떤 처리를 할 수 있도록 해주는 Java의 컴포넌트이다.

  • Spring Security의 필터는 클라이언트의 요청을 중간에서 가로챈 뒤, 보안에 특화된 작업을 처리하는 역할을 한다.

  • DelegatingFilterProxy라는 이름에서 알 수 있듯이 서블릿 컨테이너 영역의 필터와 ApplicationContext에 Bean으로 등록된 필터들을 연결해 주는 브리지 역할을 합니다.

  • Spring Security의 Filter Chain은 Spring Security에서 보안을 위한 작업을 처리하는 필터의 모음이며, Spring Security의 Filter를 사용하기 위한 진입점이 바로 FilterChainProxy입니다.

🧢 [심화] Filter와 FilterChain 구현

  • Spring Boot에서는 FilterRegistrationBean을 이용해 Filter를 등록할 수 있다.

  • Spring Boot에서 등록하는 Filter는 다음과 같은 방법으로 실행 순서를 지정할 수 있다.
    1) Spring Bean으로 등록되는 Filter에 @Order 애너테이션을 추가하거나 Orderd 인터페이스를 구현해서 Filter의 순서를 지정할 수 있다.
    2) FilterRegistrationBean의 setOrder() 메서드를 이용해 Filter의 순서를 지정할 수 있다.

🧢 [심화] DelegatingPasswordEncoder

  • 스프링 시큐리티 5.0 이전 버전부터 DelegatingPasswordEncoder를 도입해 조금 더 유연한 구조로 PasswordEncoder를 사용할 수 있게 되었다.

  • DelegatingPasswordEncoder의 장점

1) 사용하고자 하는 암호화 알고리즘을 특별히 지정하지 않는다면 Spring Security에서 권장하는 최신 암호화 알고리즘을 사용하여 패스워드를 암호화할 수 있도록 해준다.

2) 패스워드 검증에 있어서 레거시 방식의 암호화 알고리즘으로 암호화된 패스워드의 검증을 지원한다.

3) 암호화 방식을 변경하고 싶다면 언제든지 암호화 방식을 변경할 수 있다.
단 이 경우, 기존에 암호화되어 저장된 패스워드에 대한 마이그레이션 작업이 진행되어야 한다.

✏️ Chapter - Spring Security 인증 구성요소 이해

🧢 Spring Security의 인증 처리 흐름

  • 사용자의 로그인 요청을 처리하는 Spring Security Filter는 UsernamePasswordAuthenticationFilter이다.

  • UsernamePasswordAuthenticationToken은 Authentication 인터페이스를 구현한 구현 클래스이며, 여기에서 Authentication은 ⭐ 아직 인증이 되지 않은 Authentication을 의미한다.

  • AuthenticationManager는 인증 처리를 총괄하는 매니저 역할을 하는 인터페이스이고, AuthenticationManager를 구현한 구현 클래스가 ProviderManager이다.

  • UserDetails는 데이터베이스 등의 저장소에 저장된 사용자의 Username과 사용자의 자격을 증명해 주는 크리덴셜(Credential)인 Password, 그리고 사용자의 권한 정보를 포함하고 있는 컴포넌트이다.

  • UserDetails를 제공하는 컴포넌트가 바로 UserDetailsService입니다.

  • UserDetailsService는 데이터베이스 등의 저장소에서 사용자의 크리덴셜(Credential)을 포함한 사용자의 정보를 조회하여 AuthenticationProvider에게 제공한다.

  • UsernamePasswordAuthenticationFilter가 생성하는 Authentication은 인증을 위해 필요한 사용자의 로그인 정보를 가지고 있지만, ⭐ AuthenticationProvider가 생성한 Authentication은 인증에 성공한 사용자의 정보(Principal, Credential, GrantedAuthorities)를 가지고 있다.

  • 인증된 Authentication을 전달받은 UsernamePasswordAuthenticationFilter는 SecurityContextHolder를 이용해 SecurityContext에 인증된 Authentication을 저장한다. SecurityContext는 이후에 HttpSession에 저장되어 사용자의 인증 상태를 유지한다.

🧢 Spring Security의 인증 컴포넌트

  • UsernamePasswordAuthenticationFilter는 클라이언트로부터 전달받은 Username과 Password를 Spring Security가 인증 프로세스에서 이용할 수 있도록 UsernamePasswordAuthenticationToken을 생성한다.

  • AbstractAuthenticationProcessingFilter는 HTTP 기반의 인증 요청을 처리하지만 실질적인 인증 시도는 하위 클래스에 맡기고, 인증에 성공하면 인증된 사용자의 정보를 SecurityContext에 저장하는 역할을 한다.

  • Authentication은 Spring Security에서의 인증 자체를 표현하는 인터페이스이다.

  • AuthenticationManager는 이름 그대로 인증 처리를 총괄하는 매니저 역할을 하는 인터페이스이며, 인증을 위한 실질적인 관리는 AuthenticationManager를 구현하는 구현 클래스를 통해 이루어진다.

  • ProviderManager는 이름에서 유추할 수 있듯이 AuthenticationProvider를 관리하고, AuthenticationProvider에게 인증 처리를 위임하는 역할을 한다.

  • AuthenticationProvider는 AuthenticationManager로부터 인증 처리를 위임받아 실질적인 인증 수행을 담당하는 컴포넌트이다.

  • UserDetails는 데이터베이스 등의 저장소에 저장된 사용자의 Username과 사용자의 자격을 증명해 주는 크리덴셜(Credential)인 Password 그리고 사용자의 권한 정보를 포함하는 컴포넌트이며, AuthenticationProvider는 UserDetails를 이용해 자격 증명을 수행한다.

  • UserDetailsService는 UserDetails를 로드(load)하는 핵심 인터페이스이다.

  • SecurityContext는 인증된 Authentication 객체를 저장하는 컴포넌트이고, SecurityContextHolder는 SecurityContext를 관리하는 역할을 담당한다.

✏️ Chapter - Spring Security 권한 부여 구성요소 이해

🧢 Spring Security의 권한 부여 처리 흐름

  • AuthorizationFilter는 URL을 통해 사용자의 액세스를 제한하는 권한 부여 Filter이며, Spring Security 5.5 버전부터 FilterSecurityInterceptor를 대체한다.

  • AuthorizationManager는 이름 그대로 권한 부여 처리를 총괄하는 매니저 역할을 하는 인터페이스이다.

  • RequestMatcherDelegatingAuthorizationManager는 AuthorizationManager의 구현 클래스 중 하나이며, 직접 권한 부여 처리를 수행하지 않고 RequestMatcher를 통해 매치되는 AuthorizationManager 구현 클래스에게 권한 부여 처리를 위임한다.
    1) RequestMatcher는 SecurityConfiguration에서 .antMatchers("/orders/**").hasRole("ADMIN") 와 같은 메서드 체인 정보를 기반으로 생성된다.

🧢 [심화 학습] 접근 제어 표현식

📕 [Spring Security]JWT 인증(Authentication)

✏️ Chapter - JWT(JSON Web Token) 개요

🧢 토큰 기반 자격 증명

  • 세션 기반 자격 증명 방식은 서버 측에 인증된 사용자의 정보를 세션 형태로 세션 저장소에 저장하는 방식이다.

  • 세션 기반 자격 증명의 특징
    1) 세션은 인증된 사용자 정보를 서버 측 세션 저장소에서 관리한다.
    2) 생성된 사용자 세션의 고유 ID인 세션 ID는 클라이언트의 쿠키에 저장되어 request 전송 시, 인증된 사용자인지를 증명하는 수단으로 사용된다.
    3) 세션 ID만 클라이언트 쪽에서 사용하므로 상대적으로 적은 네트워크 트래픽을 사용한다.
    4) 서버 측에서 세션 정보를 관리하므로 보안성 측면에서 조금 더 유리하다.
    5) 서버의 확장성 면에서는 세션 불일치 문제가 발생할 가능성이 높다.
    6) 세션 데이터가 많아지면 질수록 서버의 부담이 가중될 수 있다.
    7) SSR(Server Side Rendering) 방식의 애플리케이션에 적합한 방식이다.

  • 토큰 기반 자격 증명 방식은 인증된 사용자의 정보를 토큰에 저장하고, 접근 권한을 부여해 접근 권한이 부여된 특정 리소스에만 접근할 수 있게 하는 방식이다.

  • 토큰 기반 자격 증명의 특징

1) 토큰에 포함된 인증된 사용자 정보는 서버 측에서 별도의 관리를 하지 않는다.
2) 생성된 토큰을 헤더에 포함해 request 전송 시, 인증된 사용자인지를 증명하는 수단으로 사용된다.
3) 토큰 내에 인증된 사용자 정보 등을 포함하고 있으므로 세션에 비해 상대적으로 많은 네트워크 트래픽을 사용한다.
4) 기본적으로 서버 측에서 토큰을 관리하지 않으므로 보안성 측면에서 조금 더 불리하다.
5) 인증된 사용자 request의 상태를 유지할 필요가 없기 때문에 서버의 확장성 면에서 유리하고, 세션 불일치 같은 문제가 발생하지 않는다.
6) 토큰에 포함되는 사용자 정보는 토큰의 특성상 암호화가 되지 않기 때문에 공격자에게 토큰이 탈취될 경우, 사용자 정보를 그대로 제공하는 셈이 되므로 민감한 정보는 토큰에 포함하지 말아야 한다.
7)기본적으로 토큰이 만료되기 전까지는 토큰을 무효화시킬 수 없다.
8) CSR(Client Side Rendering) 방식의 애플리케이션에 적합한 방식이다.

🧢 JWT(JSON Web Token)란?

  • JWT는 일반적으로 다음과 액세스 토큰(Access Token)과 리프레시 토큰(Refresh Token)을 사용자의 자격 증명에 이용합니다.

  • Access Token에는 비교적 짧은 유효 기간을 주어 탈취되더라도 오랫동안 사용할 수 없도록 하는 것이 권장된다.

  • JWT는 Header.Payload.Signature의 구조로 이루어진다.

  • Base64로 인코딩 되는 Payload는 손쉽게 디코딩이 가능하므로 민감한 정보는 포함하지 않아야 한다.

🧢 JWT의 장점과 단점

  • JWT는 많은 네트워크 트래픽을 사용하지 않도록 Payload에 많은 정보를 포함하지 않는 것이 바람직하다.

  • Payload는 base64로 인코딩 되기 때문에 토큰을 탈취하여 Payload를 디코딩하면 토큰 생성 시 저장한 데이터를 손쉽게 확인할 수 있으므로 Payload에는 민감한 정보를 포함하지 않아야 한다.

  • 토큰은 자동으로 삭제되지 않으므로 반드시 토큰 만료 시간을 지정해야 한다.

  • 토큰이 탈취될 경우를 대비해서 토큰 만료 시간을 너무 길게 설정하지 않는 것이 바람직하다.

🧢 JWT 생성 및 검증 테스트

  • Plain Text 자체를 Secret Key로 사용하는 것은 권장되지 않는다.

  • jjwt 최신 버전(0.11.5)에서는 서명 과정에서 HMAC 알고리즘을 직접 지정하지 않고, 내부적으로 적절한 HMAC 알고리즘을 지정해 준다.

✏️ Chapter - Spring Security에서의 JWT 인증

🧢 JWT 적용을 위한 사전 작업

  • Spring Security 기반의 애플리케이션에 JWT를 적용하기 위해서는 jjwt나 Java JWT 같은 별도의 라이브러리가 필요하다.

🧢 JWT 자격 증명을 위한 로그인 인증

  • UsernamePasswordAuthenticationFilter를 이용해서 JWT 발급 전의 로그인 인증 기능을 구현할 수 있다.

  • Spring Security에서는 개발자가 직접 Custom Configurer를 구성해 Spring Security의 Configuration을 커스터마이징(customizations) 할 수 있다.

  • Username/Password 기반의 로그인 인증은 OncePerRequestFilter 같은 Spring Security에서 지원하는 다른 Filter를 이용해서 구현할 수 있으며, Controller에서 REST API 엔드포인트로 구현하는 것도 가능하다.

  • Spring Security에서는 Username/Password 기반의 로그인 인증에 성공했을 때, 로그를 기록하거나 로그인에 성공한 사용자 정보를 response로 전송하는 등의 추가 처리를 할 수 있는 AuthenticationSuccessHandler를 지원하며, 로그인 인증 실패 시에도 마찬가지로 인증 실패에 대해 추가 처리를 할 수 있는 AuthenticationFailureHandler를 지원한다.

🧢 JWT를 이용한 자격 증명 및 검증 구현

  • JWT는 JWS(JSON Web Token Signed)라고도 불린다.

  • SecurityContext에 Authentication을 저장하게 되면 Spring Security의 세션 정책(Session Policy)에 따라서 세션을 생성할 수도 있고, 그렇지 않을 수도 있다.

  • SecurityContext에 클라이언트의 인증 정보(Authentication 객체)가 저장되지 않은 상태로 다음(next) Security Filter 로직을 수행하다 보면 결국에는 AuthenticationException이 발생하게 되고, 이 AuthenticationException은 AuthenticationEntryPoint가 처리하게 된다.

  • AccessDeniedHandler는 인증에는 성공했지만 해당 리소스에 대한 권한이 없으면 호출되는 핸들러이다.

profile
인자약velog

1개의 댓글

comment-user-thumbnail
2023년 12월 9일

너무 길어요 생선님

답글 달기