프록시 기술과 한계 - 의존관계 주입

현시기얌·2021년 12월 7일
0

AOP

목록 보기
17/19

프록시 기술과 한계 - 의존관계 주입

JDK 동적 프록시를 사용하면서 의존관계를 주입할 때는 문제가 발생한다.

예제 코드

@Slf4j
@Import(ProxyDIAspect.class)
@SpringBootTest(properties = {"spring.aop.proxy-target-class=false"})  // JDK 동적 프록시
public class ProxyDITest {

    @Autowired
    MemberService memberService;

    @Autowired
    MemberServiceImpl memberServiceImpl;

    @Test
    void go() {
        log.info("memberService class = {}", memberService.getClass());
        log.info("memberServiceImpl class = {}", memberServiceImpl.getClass());

        memberServiceImpl.hello("hello");
    }
}

실행 결과

타입과 관련된 예외가 발생한다.
membereServiceImpl에 주입되길 기대하는 타입은 hello.aop.member.service.MemberServiceImpl 이지만 실제 넘어온 타입은
com.sun.proxy.$Proxy51이다.

JDK 동적 프록시에 구체 클래스 타입 주입

@Autowired
MemberServiceImpl memberServiceImpl;

JDK Proxy는 MemberService를 인터페이스를 기반으로 만들어진다.
따라서 MemberServiceImpl이 타입이 뭔지 전혀 모른다.
그래서 해당 타입에 주입할 수 없다.
때문에 MemberServiceImpl = JDK Proxy가 성립되지 않는다.

CGLIB 동적 프록시에 구체 클래스 타입 주입

예제 코드

@Slf4j
@Import(ProxyDIAspect.class)
@SpringBootTest(properties = {"spring.aop.proxy-target-class=true"})  // CGLIB 동적 프록시
public class ProxyDITest {

    @Autowired
    MemberService memberService;

    @Autowired
    MemberServiceImpl memberServiceImpl;

    @Test
    void go() {
        log.info("memberService class = {}", memberService.getClass());
        log.info("memberServiceImpl class = {}", memberServiceImpl.getClass());

        memberServiceImpl.hello("hello");
    }
}

실행 결과

@Autowired 
MemberService memberService;

CGLIB Proxy는 MemberServiceIMpl 구체 클래스를 기반으로 만들어진다.
MemberServiceImpl은 MemberService 인터페이스를 구현했기 때문에 해당 타입으로 캐스팅 할 수 있다.
따라서 MemberService = CGLIB Proxy가 성립된다.

@Autowired
MemberServiceImpl memberServiceImpl;

CGLIB Proxy는 MemberServiceImpl 구체 클래스를 기반으로 만들어지므로 해당 타입으로 캐스팅 할 수 있다.
따라서 MemberServiceImpl = CGLIB Proxy가 성립된다.

정리

JDK 동적 프록시는 대상 객체인 MemberServiceImpl 타입에 의존 관계를 주입할 수 없다.
CGLIB 프록시는 대상 객체인 MemberServiceImpl 타입에 의존 관계를 주입할 수 있다.

실제로 개발할 때는 인터페이스가 있으면 인터페이스를 기반으로 의존관계를 주입 받는 것이 맞다.
DI의 장점은 DI 받는 클라이언트 코드의 변경 없이 구현 클래스를 변경할 수 있는 것이다.
이렇게 하면 인터페이스를 기반으로 의존관계를 주입 받아야 한다.
MemberServiceImpl 타입으로 의존관계 주입을 받는 것 처럼 ㄱ구현 클래스에 의존관계를 주입하면 향후 구현 클래스를 변경할 때 의존관계 주입을 받는 클라이언트의 코드도 함께 변경해야 한다.
따라서 올바르게 잘 설계된 애플리케이션이라면 이런 문제가 발생하지는 않는다.
그럼에도 불구하고 테스트, 또는 여러가지 이유로 AOP 프록시가 적용된 구체 클래스를 직접 의존관계 주입을 받아야 하는 경우가 있을 수 있다.
이때는 CGLIB를 통해 구체 클래스 기반으로 AOP 프록시를 적용하면 된다.

profile
현시깁니다

0개의 댓글