나는 한동안 내 프로젝트에서 SpringData JPA 저장소로 작업 해 왔으며 아래 사항을 알고 있습니다.
- 저장소 인터페이스에서
findByCustomerNameAndPhone()
( 도메인 개체의 필드 라고 가정)customerName
과 같은 메서드를 추가 할 수 있습니다phone
. - 그런 다음 Spring은 런타임에 위의 저장소 인터페이스 메서드를 구현하여 구현을 제공합니다 (애플리케이션 실행 중).
이것이 어떻게 코딩되었는지에 관심이 있고 Spring JPA 소스 코드 및 API를 살펴 보았지만 아래 질문에 대한 답변을 찾을 수 없습니다.
- 저장소 구현 클래스는 런타임 및 메소드에서 어떻게 생성되고 삽입됩니까?
- SpringData JPA는 메소드를 구현하고 동적으로 주입하기 위해 CGlib 또는 바이트 코드 조작 라이브러리를 사용합니까?
위의 질의에 도움을 주시고 지원되는 문서를 제공해 주시겠습니까?
답변
우선, 진행중인 코드 생성이 없습니다. 즉, CGLib도없고 바이트 코드도 생성되지 않습니다. 기본적인 접근 방식은 JDK 프록시 인스턴스가 Spring의 ProxyFactory
API를 사용하여 프로그래밍 방식으로 생성 되어 인터페이스 MethodInterceptor
를 지원하고 인스턴스에 대한 모든 호출을 가로 채서 메서드를 적절한 위치로 라우팅하는 것입니다.
- 리포지토리가 사용자 지정 구현 부분 (자세한 내용 은 참조 문서의 해당 부분 참조)으로 초기화되고 호출 된 메서드가 해당 클래스에서 구현 된 경우 호출이 여기로 라우팅됩니다.
- 메서드가 쿼리 메서드 인 경우 (확인 방법 참조
DefaultRepositoryInformation
) 저장소 별 쿼리 실행 메커니즘은 시작시 해당 메서드에 대해 실행되도록 결정된 쿼리를 시작하고 실행합니다. 이를 위해 다양한 위치에서 명시 적으로 선언 된 쿼리를 식별하려는 해결 메커니즘이 마련되어 있습니다 (@Query
메소드에서 JPA 명명 된 쿼리 사용). 결국 메서드 이름에서 파생 된 쿼리로 대체됩니다. 쿼리 메커니즘 검색에 대해서는을 참조하십시오JpaQueryLookupStrategy
. 쿼리 파생에 대한 구문 분석 논리는에서 찾을 수 있습니다PartTree
. 실제 쿼리에 대한 상점 별 번역은에서 볼 수 있습니다JpaQueryCreator
. - 위의 어느 것도 적용되지 않는 경우 실행되는 메소드는 저장소 별 저장소 기본 클래스 (
SimpleJpaRepository
JPA의 경우)에 의해 구현 된 메소드 여야 하며 호출은 해당 인스턴스로 라우팅됩니다.
라우팅 로직을 구현하는 메소드 인터셉터는 여기QueryExecutorMethodInterceptor
에서 높은 수준의 라우팅 로직을 찾을 수 있습니다 .
이러한 프록시의 생성은 표준 Java 기반 Factory 패턴 구현으로 캡슐화됩니다. 고급 프록시 생성은에서 찾을 수 있습니다 RepositoryFactorySupport
. 그런 다음 상점 별 구현은 필요한 인프라 구성 요소를 추가하여 JPA에 대해 계속 진행하여 다음과 같은 코드를 작성할 수 있습니다.
EntityManager em = … // obtain an EntityManager
JpaRepositoryFactory factory = new JpaRepositoryFactory(em);
UserRepository repository = factory.getRepository(UserRepository.class);
내가 명시 적으로 언급 한 이유는 핵심에서 해당 코드의 어떤 것도 처음에 실행되는 Spring 컨테이너를 필요로하지 않는다는 것이 분명 해져야하기 때문입니다. 클래스 패스의 라이브러리로 Spring이 필요하지만 (바퀴를 재발 명하지 않기를 원하기 때문에) 일반적으로 컨테이너에 구애받지 않습니다.
DI 컨테이너와의 통합을 용이하게하기 위해 우리는 물론 Spring Java 구성, XML 네임 스페이스 및 CDI 확장 과의 통합을 구축하여 SpringData 를 일반 CDI 시나리오에서 사용할 수 있도록했습니다.