본문 바로가기
Spring

[Spring] Spring AOP 사용 시 내부 호출 문제 해결 방법

by 개미가되고싶은사람 2024. 10. 3.

Spring AOP 사용 시 내부 호출 문제

Spring AOP를 사용할 때 내부 호출 문제는 AOP가 적용된 프록시를 통해 대상 객체(Target)를 호출해야 발생하는데, 프록시를 거치지 않고 직접 호출하면 AOP가 적용되지 않아 어드바이스가 호출되지 않는 문제가 생깁니다. 

이 문제는 @Transactional과 같은 AOP 기반 기능에서도 동일하게 발생합니다. 

해결 방법으로는 대상 객체를 직접 호출해서 발생한 문제이기 때문에 외부 호출을 하면 문제가 해결됩니다.

 

해결 방법 - 지연 조회

내부 호출을 사용한 예시

@Slf4j
@Component
public class CallServiceV0 {

    public void external() {
        log.info("call external");
        internal(); // 내부 호출
    }

    public void internal() {
        log.info("call internal");
    }
}

 

 

ApplicationContext, ObjectProvider를 사용

@Slf4j
@Component
@RequiredArgsConstructor
public class CallServiceV2 {

    1-1 private final ApplicationContext applicationContext;
    2-1 private final ObjectProvider<CallServiceV2> callServiceProvider;

    public void external() {
        log.info("call external");
    1-2 CallServiceV2 callServiceV2 = applicationContext.getBean(CallServiceV2.class);
    2-2 CallServiceV2 callServiceV2 = callServiceProvider.getObject();
        callServiceV2.internal(); //외부 메서드 호출
    }

    public void internal() {
        log.info("call internal");
    }
}

 

ApplicationContext, ObjectProvider는 객체를 스프링 컨테이너에서 조회하는 것을 스프링 빈 생성 시점이 아니라 실제 객체를 사용하는 시점으로 지연할 수 있습니다.

 

해결 방법 - 구조 변경

스프링에서도 해당 방법을 제일 권장합니다.

@Slf4j
@Component
@RequiredArgsConstructor
public class CallServiceV3 {
    private final InternalService internalService;

    public void external() {
        log.info("call external");
        internalService.internal(); //외부 메서드 호출
    }
}
@Slf4j
@Component
public class InternalService {
    public void internal() {
        log.info("call internal");
    }
}