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

이진영님의 프로필 이미지
이진영

작성한 질문수

스프링 핵심 원리 - 고급편

빈 후처리기 - 적용

spring-boot-starter-jdbc dependency 추가 시 에러

해결된 질문

작성

·

795

·

수정됨

2

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

[질문 내용]

커리큘럼 완강 후 샘플 프로젝트 만들면서 공부 중에 질문이 생겼습니다.

 

빈 후처리기 적용하는 과정 중에 추가로 jdbc dependency를 넣었습니다.

 

build.gradle 파일에

implementation 'org.springframework.boot:spring-boot-starter-jdbc'

위와 같이 추가하고 실행하면

create proxy: target class=class hello.proxy.app.v3.OrderRepositoryV3$$SpringCGLIB$$0 proxy class=class jdk.proxy2.$Proxy63

 

The bean 'orderRepositoryV3' could not be injected because it is a JDK dynamic proxy

 

OrderRepositoryV3의 target 클래스가 SpringCGLIB로 생성되서 오류가 나고

JDBC dependency를 주석 처리하고 gradle 빌드 후 다시 실행해보면 잘 실행됩니다.

 

jdbc dependency를 추가해서 오류가 발생하는 이유와 해결 방법이 궁금합니다.

 

 

답변 3

2

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

안녕하세요. 이진영님

spring-boot-starter-jdbc 라이브러리를 사용하게 되면 @Repository 애노테이션이 있는 곳에서 스프링이 추가적인 AOP를 생성하게 됩니다.

이 AOP는 JDBC 예외를 스프링 예외로 변환하는 AOP 입니다.(스프링 DB 강의 참고)

따라서 다음 순서로 작동합니다.

1. 스프링이 @Repository를 위한 프록시 적용

OrderRepositoryV3 -> OrderRepositoryV3(CGLIB 적용)

2. 우리가 직접 만든 프록시가 한번 더 적용

OrderRepositoryV3(CGLIB 적용) ->

이때 우리가 직접 만든 프록시를 적용하는 PackageLogTraceProxyPostProcessor가 사용됩니다.

여기에 입력으로 들어오는 것이 순수한 OrderRepositoryV3가 아니라 앞서 설명한 OrderRepositoryV3(CGLIB 적용)가 됩니다.

그런데 이렇게 만들어진 OrderRepositoryV3(CGLIB 적용)에는 CGLIB를 적용하면서 상위에 몇게의 인터페이스도 함께 추가됩니다.

ProxyFactory는 상위에 인터페이스가 있다면 기본으로 JDK 동적 프록시를 적용하게 됩니다.

 

해결방안1

PackageLogTraceProxyPostProcessor 코드에 setProxyTargetClass(true)를 추가합니다. 이렇게 하면 JDK 동적 프록시가 아니라 CGLIB를 통해서 구현하기 때문에 문제가 발생하지 않습니다.

// 프록시 대상이면 프록시를 만들어서 반환

ProxyFactory proxyFactory = new ProxyFactory(bean);

proxyFactory.setProxyTargetClass(true);

proxyFactory.addAdvisor(advisor);

해결방안2

실무에서는 AOP를 적용할 때 직접 PostProcessor를 통해서 프록시를 만드는 것이 아니라 스프링이 제공하는 AOP 메커니즘을 활용하면 됩니다. 이렇게 하면 프록시를 중복으로 만들지 않고 AOP를 누적해서 적용하기 때문에 이런 문제가 발생하지 않습니다.

감사합니다.

0

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

안녕하세요. 이진영님

도움을 드리고 싶지만 질문 내용만으로는 답변을 드리기 어렵습니다.

실제 동작하는 전체 프로젝트를 압축해서 구글 드라이브로 공유해서 링크를 남겨주세요.

구글 드라이브 업로드 방법은 다음을 참고해주세요.

https://bit.ly/3fX6ygx

 

주의: 업로드시 링크에 있는 권한 문제 꼭 확인해주세요

 

추가로 다음 내용도 코멘트 부탁드립니다.

1. 문제 영역을 실행할 수 있는 방법

2. 문제가 어떻게 나타나는지에 대한 상세한 설명

 

링크: 공식 서포터즈

링크: 자주하는 질문

감사합니다.

이진영님의 프로필 이미지
이진영
질문자

https://drive.google.com/file/d/1C9C8cYuZAV6XCI0BGu1I7kw_UP_3wKqt/view?usp=drive_link

 

  1. project import 후

    build.gradle에

     

     

    implementation 'org.springframework.boot:spring-boot-starter-jdbc'

    jdbc 의존성을 추가한 채로 ProxyApplication.main() 메소드 실행 시 오류 발생

     

     

target class=class hello.proxy.app.v3.OrderRepositoryV3

proxy class=class hello.proxy.app.v3.OrderRepositoryV3$$SpringCGLIB$$0

로그 출력

 

// implementation 'org.springframework.boot:spring-boot-starter-jdbc'

jdbc 의존성을 제거하거나 주석 처리하고 ProxyApplication.main() 메소드 실행 시 정상 작동

 

target class=class hello.proxy.app.v3.OrderRepositoryV3$$SpringCGLIB$$0

proxy class=class jdk.proxy2.$Proxy63

로그 출력

 

  1. build.gradle에 jdbc 의존성이 없으면 target 클래스가 OrderRepositoryV3 이고 proxy 클래스가 OrderRepositoryV3$$SpringCGLIB$$0라고 출력되면서 프로젝트가 오류 없이 실행되는데, 의존성 추가하고 프로젝트를 실행하면 target 클래스가 OrderRepositoryV3$$SpringCGLIB$$0가 되고 proxy 클래스가 jdk.proxy2.$Proxy63 라고 출력되며 프로젝트에 오류가 발생합니다.

 

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

안녕하세요. 이진영님 파일을 다시 올려주셔야 할 것 같아요.

image

0

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

질문 주신 내용과 관련하여 spring-boot-starter-jdbc 의존성을 추가했을 때 발생하는 오류와 해결 방법에 대해 이전에 비슷한 질문이 있었습니다. 강의 수강생의 질문에 대한 강사님의 답변을 아래에서 확인하실 수 있습니다.

강사님은 spring-boot-starter-jdbcspring-boot-starter-data-jpa를 사용할 때 대부분 포함되므로 생략할 수 있다고 말씀하셨습니다. 강사님의 답변을 참고하시어 문제를 해결해 보시기 바랍니다.

  • 강의 제목: 실전! 스프링 데이터 JPA
  • 질문 제목: 안녕하세요, Spring-data-JPA와 Jdbc 의존 관계 질문드립니다 !
  • 링크: 강의 게시판 질문
  • 이미지: 의존성 오류 이미지

더 궁금한 점이 있으시면 질문 게시판을 이용해 주십시오.

이진영님의 프로필 이미지
이진영

작성한 질문수

질문하기