TIL

스프링 AOP - 실무 주의사항

프록시와 내부 호출

참고로 스프링 AOP가 아닌 AspectJ를 직접 사용해서 컴파일 타임 위빙이나 로드 타임 위빙을 하면 내부 메서드를 호출해도 어드바이스가 적용된다. 하지만 이 방법은 설정이 복잡하다.

대안

프록시 기술과 한계 - 타입 캐스팅과 의존 관계 주입

스프링이 프록시를 만들 때 제공하는 ProxyFactoryproxyTargetClass 옵션에 따라 선택해서 프록시를 만들 수 있다.

JDK 동적 프록시 한계

인터페이스 기반인 JDK 동적 프록시는 구체 클래스로 타입 캐스팅이 불가능하다는 한계가 있다.

MemberServiceImpl target = new MemberServiceImpl();
ProxyFactory proxyFactory = new ProxyFactory(target);
proxyFactory.setProxyTargetClass(false); //JDK 동적 프록시

//프록시를 인터페이스로 캐스팅 성공
MemberService memberServiceProxy = (MemberService) proxyFactory.getProxy();

//JDK 동적 프록시를 구현 클래스로 캐스팅 시도 실패, ClassCastException 예외 발생
assertThrows(ClassCastException.class, () -> {
    MemberServiceImpl castingMemberService = (MemberServiceImpl) memberServiceProxy;
});

의존 관계 주입

CGLIB 단점

CGLIB는 구체 클래스를 상속 받기 때문에 다음과 같은 문제가 있다.

대상 클래스에 기본 생성자 필수

생성자 2번 호출 문제

  1. 실제 target의 객체를 생성할 때
  2. 프록시 객체를 생성할 때 부모 클래스의 생성자 호출 img.png

    fianl 키워드 사용 불가

스프링의 해결책

스프링 3.2, CGLIB를 스프링 내부에 함께 패키징

CGLIB 기본 생성자 필수 문제 해결

생성자 2번 호출 문제

스프링부트 2.0 - CGLIB 기본 사용