-
Spring: Proxy를 통한 Spring Data Repository 초기화와 설정각종 학습 요약/Spring 2022. 7. 1. 23:44
Proxy를 통한 Spring Data Repository 초기화와 설정
이 글의 카테고리를 SpringAOP로 할 지, Spring Data로 할 지, 특정 질문에 대한 답변이니까 그냥 별도의 카테고리로 할 지 고민을 하다가 그냥 Spring이라고만 적기로 했습니다. 잡담은 차치하고... 왜 이런 글을 쓰게 되었냐면요.
오늘 백엔드 부트캠프 오픈채팅의 대장님이신 은철님께서 "Spring Data JDBC의CrudRepository
는 구현체도 없는데 어떻게 쓸 수 있는거냐"라는 질문을 남겨주셨습니다.
저도 어디서 들었는지 모르겠는데 대강 알고 있는 정보로 나름의 답변을 드렸어요. 제 기억에, '프록시로 구현될걸요?'정도의 뉘앙스로 답변을 했던 거 같아요.
그런데 썩 명쾌한 답변이 된 것 같지도 않고(심지어 잘못된 것도 같고), 또 알고리즘 스터디 대장님이신 o_b:us님께서도 "혹시 어떤 자료를 참고하셨는지"하고 물어봐주셔서, 이번 기회에 조금 정리를 해보면 좋겠다는 생각이 들었어요.이 글을 읽기 위해 대강 들어본 적은 있어야하는 키워드
- 스프링 핵심 디자인 패턴: 프록시 패턴 -
ProxyFactory
를 통해 구현되는 JDK Dynamic Proxy - 스프링 바이트코드 조작 라이브러리: CGLib
- 위 두가지 모두 무엇을 위한 것인가?: Spring AOP
- 메서드 호출을 적절히 라우트 하기 위한:
MethodInterceptor
Spring AOP 두 가지 방법 간단히 살펴보기
Spring AOP는 CGLib과 JDK Dynamic Proxy로 구현하지만 그 둘을 함께 사용하는 것은 아닌데요.
표준 Java 리플렉션 패키지를 통해 구현되는 JDK Dynamic Proxy는 프록시 타겟을 찾기 위해 마커 인터페이스를 탐색합니다. 지금 저희는 리포지토리에 대한 이야길 하고 있으니, 이 상황에서는@Repository
인터페이스를 찾게 되어요(어떻게 찾을 것인가에 대해서는 FactoryBean을 더 알아보세요).
이렇게 마커 인터페이스를 갖고 있는 타겟을 찾으면 JDK Dynamic Proxy를 통해 동적으로 프록시 객체를 생성하고요, 없다면 CGLIB을 통해 바이트코드를 조작해서 프록시 객체를 생성합니다.리플렉션은 리플렉션으로 인한 오버헤드, 그리고 어노테이션을 사용해야만 한다는 점을 주의해야 하고요. CGLib은
final
에 접근할 수 없다는 점을 염두해야 합니다.Spring Data Repository를 사용하기 위한 준비
Spring Data를 실제로 사용하기 위해서는 Repository 설정을 활성화해줘야 합니다.
첫번째 방법은 xml namespace로 설정하는 것입니다.
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/data/jpa" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/data/jpa https://www.springframework.org/schema/data/jpa/spring-jpa.xsd"> <repositories base-package="com.acme.repositories" />
2. 두번째 방법은 java config file을 이용하는 방법입니다. ```xml @Configuration @EnableJpaRepositories("com.acme.repositories") class ApplicationConfiguration { @Bean EntityManagerFactory entityManagerFactory() { // … } }
- 세번째 방법은
@Repository
어노테이션을 사용하는 거에요. 익숙하실 테니까 예제는 생략할게요.
사실 그 밖에도 몇 가지 더 고려할 수 있는 방법이 있어요. Spring Data JDBC 공식문서, Spring Data JPA 공식 문서에서 확인해주세요.
그래서 어디를 봐야 되는거야
- Custom Repository를 구현하는 경우: Spring Data에 의존하지 않는 일반 스프링 빈으로 구현하는 방법이에요. 호출한 메서드가 해당 클래스에서 구현되어 있는 경우, 해당 클래스로 라우팅 됩니다. (공식 문서)
- JPA의
@Query
메서드를 사용하는 경우: DefaultRepositoryInformation을 따라 결정됩니다. - 1도 2도 모두 아닌 경우, 리포지토리별 기본 클래스(
Simple~~~Repository
)를 통해 구현되며 호출은 구현된 인스턴스로 라우팅됩니다.
2의 라우팅 로직에 대한 구현 로직이 궁금하시다면 이곳의 소스코드를 참고하세요.
질문을 남겨주신 분을 위한 답변을 남기자면 & 한 줄 답변
근데 사실 저희 학습진도 안에서는 아직
@Repository
를 사용하지 않고CrudRepository
만 상속 받고 있어요. 그리고CrudRepository
에 들어가보면@NoRepositoryBean
애노테이션이 붙어있죠. 말 그대로 실제 사용되는 Repository가 아님을 표시하기 위한 어노테이션이에요.
사실 저도 이 부분은 완전히 이해되지 않아요, 왜냐하면 공식문서 첫 파트에서는CrudRepository
가 마커 인터페이스라고 되어있는데, 막상 들어가보면@NoRepositoryBean
이 붙어있어서요(글을 쓰다보니까, 둘이 상관 없는거 아닌가?하는 생각이 갑자기... 일단 글은 마무리 해놓고 더 알아봐야겠어요). 그래서 당장은, 실제 빈을 만들지 않고, 구현체에 기능을 넘겨주기위한 목적으로만 존재하는 인터페이스인 것이라는 점만 기억하고 넘어가기로 했습니다.그래서 답변의 요점은?
Repository 관련 메서드 콜은 JDK Dynamic Proxy를 통해 기본 클래스를 프록시 한 인스턴스로 라우팅 된다, 입니다.'각종 학습 요약 > Spring' 카테고리의 다른 글
API 호출을 위한 세 가지 Spring 도구(Spring 6에서 새롭게 지원하는 HttpInterface) (0) 2023.03.17 Spring : 이벤트 리스너 기본 개념 (@EventListener, @TransactionalEventListener) (2) 2022.07.11 Spring: AOP의 기본적인 개념 & SpringAOP 훑어보기 (2) 2022.06.20 Error Handling: Spring에서 Exception 대응하기 (0) 2022.06.17 Spring: 의존관계 주입(DI, Dependency Injection) 방식 네 가지 요약 (0) 2022.06.16 Spring: IoC와 DI를 예시로 쉽게 이해해보자 (0) 2022.06.16 - 스프링 핵심 디자인 패턴: 프록시 패턴 -