ArgumentResolver
HandlerMethodArgumentResolver
Spring MVC에서 컨트롤러 메서드의 각 파라미터가 어떻게 해석되어야 할지 결정하는 전략을 제공하는 인터페이스
즉, HTTP 요청과 관련된 데이터를 어떤 방식으로 컨트롤러 메서드의 인자로 전달할지 결정하는 역할을 함
-> (@RequestParam, @PathVariable 등) 으로 처리할 수 없는, 더 복잡하거나 특수한 요구사항을 가진 파라미터 바인딩을 구현할 수 있다.
ArgumentResolver
- HandlerMethodArgumentResolver의 구현체를 지칭하는 말
HandlerMethodArgumentResolver 인터페이스는 주로 두 가지 메소드를 정의한다.
핵심메소드
- supportsParameter(MethodParameter parameter): 이 메서드는 현재 Resolver가 주어진 컨트롤러 메서드 파라미터를 지원하는지 여부를 판단한다. 즉, 파라미터 타입이나 어노테이션 등을 검사하여 이 Resolver가 해당 파라미터에 대한 처리를 수행할 수 있는지 결정한다.
- resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory): 이 메서드는 실제로 파라미터를 해석하는 로직을 구현한다. 주어진 MethodParameter에 대해 적절한 인자 값을 반환해야 하며, 이 값은 컨트롤러 메서드의 해당 파라미터로 사용된다.
스프링 MVC 요청 처리 흐름
- HTTP 요청 수신: 스프링 MVC 애플리케이션은 클라이언트로부터 HTTP 요청을 받는다.
- DispatchServlet: 모든 요청은 먼저 스프링의 DispatcherServlet을 통과한다. DispatcherServlet은 요청을 적절한 컨트롤러로 라우팅하는 중앙 집중식 진입점
- 핸들러 매핑(Handler Mapping): DispatcherServlet은 핸들러 매핑을 사용하여 요청을 처리할 컨트롤러 메서드를 찾는다.
- 핸들러 인터셉터(Handler Interceptor) 전처리: 요청이 컨트롤러에 도달하기 전, 구성된 핸들러 인터셉터가 먼저 실행된다. 인터셉터는 사전 처리를 할 수 있다.
- HandlerMethodArgumentResolver 실행: 요청이 매핑된 컨트롤러 메서드에 도달하기 직전, 스프링은 해당 메서드의 파라미터 타입을 확인하고, 필요한 경우 HandlerMethodArgumentResolver를 사용하여 파라미터 값을 결정하고 준비 - supportsParameter: 먼저, 스프링은 등록된 모든 HandlerMethodArgumentResolver를 순회하면서, 각 Resolver가 현재 파라미터를 지원하는지 확인한다. - resolveArgument: 지원하는 Resolver가 발견되면, 해당 Resolver의 resolveArgument 메서드가 호출되어 실제 파라미터 값을 생성한다.
- 컨트롤러 메서드 실행: 모든 파라미터가 해석되고 준비되면, 최종적으로 컨트롤러 메서드가 호출되어 비즈니스 로직이 실행된다.
- 핸들러 인터셉터(Handler Interceptor) 후처리: 컨트롤러 메서드 실행 후, 후처리를 위해 핸들러 인터셉터가 다시 실행될 수 있다.
- 뷰 렌더링: 컨트롤러에서 반환된 모델과 뷰 정보를 바탕으로 응답이 렌더링되고 클라이언트로 반환된다.
JPA
데이터베이스
데이터를 효율적으로 보관하고 꺼내 볼 수 있는 곳, 데이터를 안전하게 사용하고 관리하기 위해 사용한다.
데이터베이스를 관리하기 위한 소프트웨어를 DBMS(database management system)라고 하며, 관리하는 방식에 따라서 관계형, 객체-관계형, Document형, 비관계형 등으로 분류 된다.
가장 많이 사용하는 DBMS는 관계형이다.
관계형 DBMS는 RDBMS(Relational DBMS)라고 부르며, 테이블 형태로 이루어진 데이터 저장소이다.
예를 들어, 회원 테이블이 있다고 가정하면 각 행은 고유의 키, 즉 아이디를 가지고 있고, 이메일, 나이 등과 같은 회원과 관련된 값들이 들어간다.
용어
테이블 : 데이터를 구성하기 위한 가장 기본적인 단위, 행과 열로 구성
행 : 테이블의 가로로 배열된 데이터의 집합, 반드시 고유한 식별자인 기본 키를 가진다.
열 : 행에 저장되는 유형의 데이터, 각 요소에 대한 속성을 나타내며 무결성을 보장
기본 키(Primary key) : 행을 구분할 수 있는 식별자, 이 값은 테이블에서 유일해야 하며 중복 값을 가질 수 없다.
기본 키의 값은 수정되어서는 안 되며 유효한 값이어야 한다. 즉 NULL이 될 수 없다.
쿼리 : 데이터 베이스에서 데이터를 조회하거나 삭제, 생성, 수정같은 처리를 하기 위해 사용하는 명령문.
트랜잭션 : 데이터베이스의 상태를 변화시키기 위해 수행하는 작업의 단위
하나의 트랜잭션은 하나 이상의 연산(삽입, 갱신, 삭제 등)을 포함할 수 있으며, 이러한 연산들은 모두 함께 성공적으로 완료되거나, 하나라도 실패할 경우 전체가 취소(롤백)되어야 하는 논리적인 작업의 단위이다.
ORM
ORM(Object-relational mapping)은 Java의 객체와 데이터베이스를 연결하는 프로그래밍 기법
데이터베이스의 값을 마치 객체처럼 사용할 수 있다.
JPA와 Hibernate
DBMS에도 여러 종류가 있는 것 처럼 ORM에도 여러 종류가 있는데
Java에서는 JPA(Java persistence API)를 표준으로 사용한다.
JPA는 자바에서 관계형 데이터베이스를 사용하는 방식을 정의한 인터페이스이고
이 인터페이스를 사용하기 위해서 ORM 프레임워크를 사용해야하는데, 대표적으로 Hibernate를 많이 사용한다.
Hibernate는 JPA 인터페이스를 구현한 구현체이자 자바용 ORM 프레임워크이며, 내부적으로는 JDBC API를 사용한다.
Hibernate의 목표는 자바 객체를 통해 데이터베이스 종류에 상관없이 데이터베이스를 자유롭게 사용할 수 있게 하는데 있다.
JPA → Java 객체와 데이터베이스를 연결해 데이터를 관리한다. 객체 지향 도메인 모델과 데이터베이스를 잇는 역할을 한다.
Hibernate → JPA의 인터페이스를 구현한다. 내부적으로는 JDBC API를 사용한다.
엔티티 매니저, 영속성 컨텍스트
JPA의 중요한 컨셉인 엔티티 매니저와 영속성 컨텍스트에 대해 알아보자.
엔티티
엔티티는 데이터베이스의 테이블과 매핑되는 객체를 의미한다.
엔티티는 객체이지만 데이터베이스에 영향을 미치는 쿼리를 실행하는 객체이다.
엔티티 매니저
엔티티를 관리해 데이터베이스와 애플리케이션 사이에서 객체를 생성, 수정, 삭제하는 등의 역할을 하며,
엔티티 매니저를 만드는 곳이 엔티티 매너지 팩토리(Entity manager factory)이다.
데이터베이스에는 여러 사용자가 동시에 접근할 수 있다.
예를 들어 회원 2명이 동시에 회원 가입을 하는 경우, 엔티티 매니저는 다음과 같이 요청을 처리한다.
1. 회원 1의 요청에 대해서 가입 처리를 할 엔티티 매니저를 엔티티 매니저 팩토리가 생성하면 이를 통해 가입 처리해 데이터 베이스에 회원 정보를 저장한다.
2. 회원 2에 대해서 1을 반복한다.
Springboot에서는 내부에서 엔티티 매니저 팩토리를 하나만 생성해서 관리하고
@PersistenceContext, @Autowired 애너테이션을 사용하여 엔티티 매니저를 사용한다.
스프링 부트는 기본적으로 빈은 하나만 생성해서 공유하므로 동시성 문제가 발생할 수 있어서 실제로는 엔티티 매니저가 아닌 실제 엔티티 매니저와 연결하는 프록시(가짜) 엔티티 매니저를 사용한다.
영속성 컨텍스트
엔티티 매니저는 엔티티를 영속성 컨텍스트에 저장한다는 특징이 있다.
영속성 컨텍스트는 엔티티를 관리하는 가상의 공간이다.
영속성 컨텍스트에는 1차 캐시, 쓰기 지연, 변경 감지, 지연 로딩이라는 특징이 있다.
1차 캐시
영속성 컨텍스트는 내부에 1차 캐시를 가지고 있다.
이때 캐시의 키는 엔티티의 @Id 애너테이션이 달린 기본 키 역할을 하는 식별자이며 값은 엔티티이다.
엔티티를 조회하면 1차 캐시에서 데이터를 조회하고 값이 있으면 반환한다.
값이 없으면 데이터베이스에서 조회해 1차 캐시에 저장한 뒤 반환한다.
쓰기 지연
트랜잭션을 커밋하기 전까지는 데이터베이스에 실제로 질의문을 보내지 않고 쿼리를 모았다가 트랜잭션을 커밋하면 모았던 쿼리를 실행하는 것을 의미한다.
-> 적당한 묶음으로 쿼리를 요청할 수 있어 불필요한 통신을 줄이고 데이터베이스 시스템의 부담을 줄일 수 있다.
변경 감지
트랜잭션을 커밋하면 1차 캐시에 저장되어 있는 엔티티의 값과 현재 엔티티의 값을 비교해서 변경된 값이 있다면 변경사항을 감지해 변경된 값을 데이터베이스에 자동으로 반영한다.
지연 로딩
쿼리로 요청한 데이터를 애플리케이션에 바로 로딩하는 것이 아니라 필요할 때 쿼리를 날려 데이터를 조회하는 것을 의미
Spring data JPA
Spring data JPA는 Spring data의 인터페이스인 PagingAndSortingRepository를 상속받아 JpaRepository를 만들었으며, JPA를 더 편리하게 사용하는 메서드를 제공한다.
Repository는 엔티티에 있는 데이터들을 조회하거나 저장, 변경, 삭제를 할 때 사용하는 인터페이스로, 스프링 데이터 JPA에서 제공하는 인터페이스인 JPARepository 클래스를 상속받아 간단히 구현할 수 있다.
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
JPA 10
@Service
public class MemberService {
@Autowired
MemberRepository memberRepository;
public void test() {
// 생성
memberRepository.save(new Member(1L, "A"));
// 조회
Optional<Member> member = memberRepository.findById(1
List<Member> allMembers = memberRepository.findAll();
// 삭제
memberRepository.deleteById(1L);
}
}
1. save() 메서드를 호출해 데이터 객체를 저장할 수 있다. 전달 인수로 엔티티 Member 를 넘기면 반환값으로 저장한 엔티티를 반환받는다.
2. findById() 메서드에 id를 지정해 엔티티를 하나 조회할 수 있다. findAll() 메소드 는 전체 엔티티를 조회한다.
3. deleteById() 메서드에 id를 지정하면 엔티티를 삭제할 수 있다.
mport jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Entity
JPA 11
// @Entity(name = "member_list")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", updatable = false)
private Long id;
@Column(name = "name", nullable = false)
private String name;
}
1. @Entity 애너테이션은 Member 객체를 JPA가 관리하는 Entity로 지정한다.
2. @Id는 Long 타입의 id 필드를 테이블의 기본 키로 지정한다.
3. @GeneratedValue는 기본키의 생성 방식을 결정한다.
4. @Column 애너테이션은 데이터베이스의 컬럼과 필드를 매핑해준다.
'🚣활동 > 멋쟁이사자처럼' 카테고리의 다른 글
구글맵 API 이용하기, Heroku로 배포하기 (0) | 2024.08.19 |
---|---|
[멋사 12기 중앙해커톤 참여] (0) | 2024.08.09 |
[멋쟁이사자처럼] 3주차 정기세션 (0) | 2024.03.24 |
[멋쟁이사자처럼] 2주차 정기세션 (0) | 2024.03.14 |
[멋쟁이사자처럼] 1주차 정기세션 - 2 (0) | 2024.03.13 |