JPA에서 DB의 데이터를 객체로 어떻게 맵핑하나 공부하다보면 리플렉션에 대해서 알게된다.
오늘은 이 리플렉션에 대해서 알아보겠다.
참고로 하이버네이트는 JPA가 Spring 진영의 공식 ORM이 되기 전에 있었던 오픈소스 ORM 라이브러리 이름이다. JPA를 공부하다보면 하이버네이트의 흔적이 곳곳에서 보이곤한다.
자바 리플렉션 API는 클래스의 메타데이터(구조)를 분석하여 private 접근제어를 무너뜨리고 데이터를 직접 주입할 수 있다.
자바 가상 머신(JVM)은 클래스를 실행할 때 해당 클래스의 모든 정보(필드 이름, 타입, 메서드 등)를 메모리의 메서드 영역(Method Area)에 저장해둔다. 일반적인 컴파일에서는 접근제어권한을 풀 수 없지만 리플렉션은 런타임에 메모리에 저장된 클래스 정보 자체
를 직접 건드리는 방식이기 때문에 가능하다.
일반적으로 private 필드는 외부에서 접근하려고 하면 캡슐화 규칙으로 인해 IllegalAccessException을 던진다.
리플렉션 API에는 field.setAccessible(true) 메서드가 있는데 호출하면 private 필드에 직접 값을 쓰고 읽을 수 있게 만든다. 하이버네이트는 우선 자바 클래스의 어떤 필드의 접근제어권한을 해제할지 파악하기 위해 @Id나 @Column이 붙은 타겟 필드를 찾아낸 뒤, 해당 필드에 field.setAccessible(true) 메서드를 호출한다. 그럼 JVM은 이 필드에 대해서는 캡슐화 규칙을 적용하지 않는다.
하이버네이트의 주입 과정
- 객체 생성: @NoArgsConstructor(access = PROTECTED)를 사용하여 엔티티의 빈 인스턴스를 만든다. (이때 필드는 모두 null이나 기본값)
- 필드 정보 추출: 클래스 메타데이터에서 @Id, @Column 등이 붙은 필드들을 찾는다.
- 값 바인딩: DB에서 읽어온 값(ResultSet)을 해당 필드의 타입에 맞게 변환한다.
- 직접 주입: field.set(instance, value)를 호출하여 Setter 메서드 없이도 필드에 직접 값을 넣는다.
하이버네이트가 setter를 만들어 의존성을 주입하는 대신 리플렉션 방식을 선택한 이유는 비즈니스 로직을 지키기 위해 개발자가 setter를 선택하지 않을 수 있기 때문이다. 하이버네이트가 리플렉션을 채용함으로 인해 우리는 OCP 확장에는 열려있지만 변경에는 닫혀있는 객체지향의 원칙을 지킬 수 있게 되었다.
'Java > Spring' 카테고리의 다른 글
| Spring 처음 시작할 때 설정 (0) | 2024.08.28 |
|---|---|
| Fetch Join(1) - 개요 및 Join과의 차이점 (0) | 2024.08.20 |
| 트랜잭션(@Transaction) (2) - 트랜잭션 옵션 (0) | 2024.08.07 |
| 트랜잭션(@Transaction) (1) - 트랜잭션의 개요 및 프록시 내부 호출 문제 (0) | 2024.08.06 |
| 그거 아셨나요? - 체크 예외(Check Exception) (0) | 2024.07.28 |