기술노트/백엔드.스프링부트

Spring JPA Repository 이해. 핵심 정리 | 업캐스팅, @Autowired

newlamb 2025. 4. 11. 21:23

Spring Boot와 JPA를 활용한 백엔드 개발에서는 JpaRepository, 인터페이스, 업캐스팅, @Autowired 주입 방식 등을 이해하는 것이 매우 중요합니다. 이 글에서는 비전공자나 초보자도 이해할 수 있도록 핵심 개념들을 순차적으로 정리합니다.

 

 

 

📌 1. 왜 BookRepository를 인터페이스로 선언할까?

public interface BookRepository extends JpaRepository<Book, Long> { }

🔍 이유:

  • JpaRepository는 Spring Data JPA에서 제공하는 인터페이스로, CRUD 기능을 기본으로 제공
  • 우리가 BookRepository를 인터페이스로 만들고 JpaRepository를 상속하면, Spring이 이 인터페이스의 프록시 구현체를 자동으로 생성해서 빈으로 등록함
  • 개발자는 구현 없이도 Repository 사용 가능!

📘 2. JpaRepository는 인터페이스다. 그럼 추상 메서드는 어떻게 동작할까?

JpaRepository는 수많은 추상 메서드를 포함하고 있지만, 우리는 직접 구현하지 않습니다.

✨ Spring 내부 동작

  • Spring이 런타임 시 JpaRepository를 구현한 클래스를 자동 생성함 (보통 SimpleJpaRepository)
  • 이를 통해 인터페이스만 작성해도 CRUD 기능이 자동 제공

🔁 3. 인터페이스 간에도 상속이 가능한가요?

가능합니다!

public interface A { void methodA(); } public interface B extends A { void methodB(); }
  • 인터페이스 → 인터페이스는 extends로 상속
  • 클래스 → 인터페이스는 implements로 구현

 


🧠 4. 업캐스팅(Upcasting)의 개념과 사용 이유

BookRepository bookRepository = new EntityManager();

위 문장은 EntityManager가 BookRepository를 구현한 클래스일 경우 유효합니다.

✅ 업캐스팅이란?

  • 자식 객체를 부모 타입으로 참조하는 것
  • 목적: 유연한 코드, 의존성 주입(DI) 가능
인터페이스 변수 = 구현체 객체
  • 이 구조 덕분에 Spring이 BookRepository 타입에 맞는 프록시 객체를 자동 주입할 수 있습니다.

📥 5. @Autowired로 주입할 때 실제로 무슨 일이 일어날까?

@Autowired private BookRepository bookRepository;

작동 흐름:

  1. Spring이 BookRepository 타입의 빈을 찾음
  2. 내부적으로는 SimpleJpaRepository 기반의 프록시 객체가 자동 생성됨
  3. 그 객체가 bookRepository에 자동 주입됨

🔁 DI(의존성 주입) 메커니즘이 핵심입니다.


🔍 6. 생성자 주입 vs 필드 주입 (@Autowired)

방식특징장점
필드 주입 @Autowired 붙이기만 하면 됨 간단하지만 테스트 어려움
생성자 주입 생성자 통해 직접 주입 불변성 보장, 테스트 용이, 순환 참조 방지에 유리

📢 요즘은 생성자 주입이 강력히 권장됩니다.


🔑 7. extends vs implements 차이

키워드대상의미
extends 클래스 → 클래스
인터페이스 → 인터페이스
상속 (코드 물려받기)
implements 클래스 → 인터페이스 구현 (메서드 내용 작성 필요)

☑️ 핵심 요약

개념설명
JpaRepository JPA에서 CRUD 기본 제공하는 인터페이스
인터페이스 상속 interface B extends A 가능
업캐스팅 자식 객체를 부모 타입으로 참조하는 것
프록시 객체 Spring이 생성한 구현체 (SimpleJpaRepository 기반)
@Autowired 자동 주입, 의존성 관리 핵심 어노테이션
생성자 주입 테스트 편하고 불변성 유지 가능
extends / implements 상속 / 구현 키워드

💬 마무리

Spring JPA에서 Repository를 인터페이스로 만들고 JpaRepository를 상속하는 구조는 유지보수, 테스트, 생산성측면에서 아주 강력한 패턴입니다.
그 기반이 되는 업캐스팅, 인터페이스 상속, 프록시 주입 개념을 잘 이해하면, Spring의 DI 철학과 구조를 자연스럽게 받아들일 수 있게 됩니다.


📚 추천 학습 키워드

  • Spring IoC / DI
  • 프록시 패턴
  • Bean Lifecycle
  • SOLID 원칙 (특히 OCP)
  • 자바 인터페이스 / 다형성

 

📊 Spring Data JPA 전체 동작 구조 & 흐름도 정리

🔄 전체 흐름 요약: Repository 생성부터 의존성 주입까지

[BookRepository 인터페이스]
        ↓ extends
[JpaRepository 인터페이스]
        ↓ 런타임 시 Spring 내부 처리
[SimpleJpaRepository 구현체 생성]
        ↓
[프록시 객체 생성 (Proxy)]
        ↓
[Spring 컨테이너에 Bean으로 등록]
        ↓
[Service에서 @Autowired or 생성자 주입]

📌 각 단계별 핵심 설명

✅ 1. 사용자 정의 Repository 인터페이스

public interface BookRepository extends JpaRepository<Book, Long> {}
  • 사용자가 직접 구현 안 해도 됨
  • Spring이 자동으로 구현체를 생성

✅ 2. JpaRepository 인터페이스

public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID> {
    // save, findById, delete 등 수많은 추상 메서드 포함
}
  • 다형성 + 제네릭 덕분에 모든 엔티티에서 재사용 가능
  • 내부적으로는 SimpleJpaRepository라는 클래스가 실제 구현체

✅ 3. Spring이 내부에서 구현체 생성 (프록시 방식)

BookRepository ← SimpleJpaRepository ← Repository 프록시 객체
  • Spring은 BookRepository의 구현체를 만들지 않음
  • 대신 SimpleJpaRepository 기반으로 프록시 객체를 생성해서 주입

📌 이게 바로 Spring Data JPA의 프록시 기반 동적 구현 전략


✅ 4. DI 컨테이너에서 Bean 등록 및 주입

@Autowired
private BookRepository bookRepository;
  • Spring이 BookRepository 타입의 프록시 객체를 자동으로 주입
  • 또는 생성자 주입 방식 사용 가능

🖼️ 시각화: 전체 흐름도 다이어그램

사용자 작성
┌──────────────────────────────┐
│ interface BookRepository     │
│ extends JpaRepository        │
└──────────────────────────────┘
              │
              ▼
Spring 내부 처리
┌──────────────────────────────┐
│ interface JpaRepository      │
│ extends PagingAndSorting...  │
└──────────────────────────────┘
              │
              ▼
Spring이 구현체 생성
┌──────────────────────────────┐
│ class SimpleJpaRepository    │
│ implements JpaRepository     │
└──────────────────────────────┘
              │
              ▼
프록시 객체 생성 (동적 Proxy)
┌──────────────────────────────┐
│ Proxy(BookRepository)        │
│ Bean으로 등록됨              │
└──────────────────────────────┘
              │
              ▼
Service 등에서 주입
┌──────────────────────────────┐
│ @Autowired 또는 생성자 주입 │
│ private BookRepository repo; │
└──────────────────────────────┘

🧠 이 흐름이 중요한 이유

이유설명
유지보수성 인터페이스로 설계하면 구현체가 바뀌어도 코드 수정 최소화
테스트 용이성 Mock 객체 주입이 쉬움
생산성 직접 구현 없이도 CRUD 기능 자동 제공
프레임워크 철학 DI(의존성 주입), IoC(제어의 역전), OCP(개방-폐쇄 원칙) 실현

 


✅ 결론

Spring JPA의 Repository 구조는 "인터페이스 기반 설계 + 프록시 동적 생성 + DI 주입"이라는 강력한 조합으로 구성됩니다.
전체 흐름을 이해하고 나면, 복잡해 보이던 구조가 오히려 깔끔하고 유연하게 느껴질 거예요.