인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

11 1님의 프로필 이미지
11 1

작성한 질문수

스프링 DB 2편 - 데이터 접근 활용 기술

JPA 적용3 - 예외 변환

@Repository를 통해 프록시가 생성되려면

해결된 질문

작성

·

72

·

수정됨

0

[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? (예)
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)
3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)

[질문 내용]
"@Repository가 붙은 클래스는 예외 변환 AOP의 적용 대상이 된다."는 내용에 대해 더 궁금한 점이 있습니다.

 

테스트 코드의 @Transactional를 주석 처리하고, @Import로 설정도 수정해서, JPA 대신 MyBatis나 JdbcTemplate을 적용해 봐도

log.info("repository = {}", itemRepository.getClass());

테스트의 이 코드를 실행하면 itemRepository가 프록시로 생성된다는 것을 확인할 수 있었습니다. JPA가 아니라 해도 @Repository가 적용되면 프록시 객체로 생성되는 것 같습니다.

 

그런데 이전 스프링 핵심 원리 기본 편 강의에서 사용했던 core 프로젝트에서도 한번 테스트해 봤는데

//@Component
@Repository
public class MemoryMemberRepository implements MemberRepository {
.
.
.
}

 

class OrderServiceImplTest {

    @Test
    void createOrder() {
        MemoryMemberRepository memberRepository = new MemoryMemberRepository();
        System.out.println(memberRepository.getClass());
.
.
.
}
}

 

이 테스트를 실행해 보면 memoryMemberRepository는 @Repository가 적용되어 있음에도 불구하고 프록시 객체로 생성되지 않는 것 같습니다.

 

이 이유가 무엇인가요?

@Repository를 통해 프록시 객체를 만드는 기능은 JPA 라이브러리가 있어야(JPA를 사용하지 않고 MyBatis를 사용하더라도) 적용되는 건가요?

 

+) 그런데 스프링 DB 1편 강의에서 사용한 프로젝트에서도 테스트해 봤는데, 여기선 JPA 라이브러리를 받지 않았는데도 @Repository를 통해 프록시 객체가 생성되는 것 같습니다. 물론 @Transactional도 주석 처리했습니다.

@Slf4j
@Repository
public class MemberRepositoryV5 implements MemberRepository {

    private final JdbcTemplate template;
.
.
.
}

 

@Test
void AopCheck() {
    log.info("memberService class = {}", memberService.getClass());
    log.info("memberRepository class = {}", memberRepository.getClass());
    Assertions.assertThat(AopUtils.isAopProxy(memberService)).isTrue();
    Assertions.assertThat(AopUtils.isAopProxy(memberRepository)).isFalse();
}

@Transactional을 주석 처리했으므로 memberService는 프록시 객체가 아니고,

@Repository가 적용된 memberRepository는 CGLIB 관련 내용이 출력됩니다.

 

@Repository를 통해 프록시 객체가 생성되려면 어떤 조건이 필요한지 궁금합니다.

답변 2

2

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. 11 1님

강의 5. 데이터 접근 기술 - JPA -> JPA 적용3 - 예외 변환에서 설명한 PersistenceExceptionTranslationPostProcessor가 있어야 @Repository에 AOP를 적용합니다.

PersistenceExceptionTranslationPostProcessor는 spring-tx(트랜잭션 관련) 라이브러리에 포함되어 있는데요. 스프링 부트는 이 클래스가 라이브러리에 있으면 자동으로 스프링 빈으로 등록하고 이 클래스를 통해 @Repository에 AOP를 적용합니다.

그리고 spring-tx는 spring-jdbc, spring-data-jpa 같은 스프링 라이브러리를 사용할 때 함께 라이브러리에 포함됩니다.

스프링 핵심 원리 기본편 강의에서는 jdbc, jpa 같은 기능을 사용하지 않았기 때문에 spring-tx 라이브러리가 빠지게 되므로 해당 기능이 활성화되지 않았습니다.

감사합니다.

11 1님의 프로필 이미지
11 1
질문자

답변 감사합니다!

 

저도 PersistenceExceptionTranslationPostProcessor 이거 때문인가 싶었는데 Persistence라는 이름 때문에 JPA 라이브러리 쪽이라고 생각해 버려서, 스프링 DB 1편 강의에서 사용한 프로젝트에서 프록시가 적용되는 이유가 설명이 안 된다고 생각했는데 JDBC를 사용해도 등록되는 거였군요..

 

감사합니다.

0

안녕하세요, 인프런 AI 인턴입니다.

11 1님께서 질문하신 내용에 대해 답변해 드리겠습니다.

@Repository 애노테이션이 적용된 클래스가 프록시 객체로 생성되는 것은 JPA와 같은 특정 기술에 국한되지 않습니다. @Repository는 Spring의 예외 변환(AOP를 통한)을 지원하며, 이것은 프록시 패턴과 결합하여 발생할 수 있는 것입니다. 하지만 프록시 객체가 생성되는지 여부는 Spring이 특정한 AOP 설정이나 라이브러리가 활성화되어 있느냐에 따라 달라집니다.

스프링이 프록시를 생성하는 데는 몇 가지 조건이 필요합니다:
1. AOP 설정: Spring AOP 설정이 활성화되어 있어야 합니다. @EnableTransactionManagement와 같은 애노테이션이 사용되었는지 확인해 보세요.
2. 트랜잭션 관리: @Transactional과 같은 트랜잭션 관련 설정이 활성화되어 있어야 합니다. 이는 트랜잭션이 필요한 경우에 자동으로 프록시가 생성되는 방식입니다.
3. 적절한 스프링 컨텍스트: 프록시 객체는 컨텍스트에 의해 관리될 때, 즉 Spring IoC 컨테이너에 빈으로 등록될 때 생성됩니다.

예를 들어, MemoryMemberRepository의 경우, 직접 인스턴스를 생성했기 때문에 Spring 컨텍스트에서 관리되지 않고, 따라서 프록시로 생성되지 않습니다.

마지막으로, JPA나 MyBatis 등과 같은 특정한 기술을 사용하지 않아도 @Repository 자체로는 프록시가 생성되지 않습니다. 그러한 기술과 관련한 설정이나 AOP 설정이 필요합니다.

추가로, @Transactional이 주석 처리되었더라도, 다른 AOP 설정에 의해 프록시가 생성될 수 있습니다. 현재 설정에 주의 깊게 보세요.

이 점들을 염두에 두면 Spring 환경에서의 프록시 생성 원리를 이해하는데 도움이 될 것 같습니다.

감사합니다. 🏷️

관련 링크: Spring AOP 및 예외 변환

11 1님의 프로필 이미지
11 1

작성한 질문수

질문하기