Spring/AOP

AOP란?

푸라멘 2024. 4. 14. 23:50

AOP(Aspect Oriented Programming) 란?

관점 지향 프로그래밍이라고 불리며

어떤 로직을 기준으로 핵심적인 관점(core concerns), 부가적인 관점(cross-cutting concerns)으로 나누어 모듈화 하는 방법을 말한다.

 

 

 

AOP 예시

회원가입기능을 만들고 회원가입 기능의 성능을 확인하기 위해 소요시간이 얼마나 걸렸는지 계산하는 로직을 추가하고 싶다.

 

public class MemberService {

    private  MemberRepository memberRepository;

    @Autowired
    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    public Long join(Member member) {

        long start = System.currentTimeMillis();

        try {
            validateDuplicateMember(member);
            memberRepository.save(member);
            return member.getId();
        } finally {
            long finish = System.currentTimeMillis();
            long timeMs = finish - start;
            System.out.println("join time => " + timeMs + "ms");
        }

    }
}

 

위 코드는 다음과 같은 문제가 있다.

  • 시간을 측정하는 로직(cross-cutting concerns) 과 핵심 로직(core concerns)이 섞여 유지보수가 어렵다.
  • join 외 다른 메서드에 시간측정 로직을 추가하고 싶다면 메서드마다 하나하나 시간 측정로직을 추가해야하고 시간측정로직의 변경이 있다면 모든 메서드를 찾아가 로직 변경을 해줘야한다.
  • 시간을 측정하는 공통로직을 별도의 공통 로직으로 만들기 매우 어렵다.

 

 

 

AOP 적용

@Aspect
@Component
//bean 등록을 해줘야한다.
public class TimeTraceAop {

    // @Around로 target을 정한다.
    @Around("execution(* com.example.bootpractice..*(..))")
    public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        try {
            // 실행할 실제 객체의 메서드 실행
            Object result = joinPoint.proceed();
            return result;
        } finally {
            long finish = System.currentTimeMillis();
            long timeMs = finish - start;
            System.out.println("END : " + joinPoint.toString() +  " " + timeMs + " ms" );
        }
    }
}

 

@Aspect

  • AOP역할을 할 클래스를 선언하기 위한 어노테이션
  • advice와 pointcut 이 함께 존재
    • advice :  프록시가 호출하는 부가 기능, 프록시가 적용할 cross-cutting concerns 로직 이다. (execute 메서드 부분 )
    • pointcut : 필터링 할 위치를 지정하느 필터링 로직, 어디에 cross-cutting concerns를 적용할지 결정 (@Around 부분)

@Around 

  • 메서드 호출 전후로 advice를 수행
  • @Before(호출 전)이나 @After(호출 후)으로 이용해서 지정할 수 있다.
  • pointcut 표현식으로 adivce를 적용할 method를 명시

ProceedingJointPoint

  • 호출 되는 대상 객체에 대한정보, 실행되는 메서드에 대한 정보 등이 들어있는 클래스
  • 원리 
    • SpringBoot의 자동 설정으로 AnnotationAwareAspectAutoProxyCreator라는 자동프록시 생성기가 빈으로 등록됨
    • 자동프록시 생성기가 @Aspect가 붙은 클래스를보고 Advisor로 변환해 저장
    • 변환된 Advisor를 보고 pointcut의 대상이되는 메서드를 ProxyFactory에 인자로 넘겨 자동으로 프록시 생성
    • 생성된 프록시가 메서드 호출시 ProceedingJoinPoint 객체 생성 후 Advice에 전달

 

 

 

AOP 동작 방식

  • Controller가 MemberService에 Method를 호출하면  프록시 MeberService를 호출하고 프록시 MeberService가 실제 MemberSerivide의 메서드를 호출한다.
  • 즉, Meberservice를 주입 받을 때 @Aspect로 인하여 생성된 프록시 MemberService를 실제 MeberService 대신 주입받아 사용한다. (DI)

 

- 다음은 MemberController에 MemberSerivice를 주입 할 떄 MemberService.Class를 출력해 본 내용이다.

AOP 적용 전 MemberService

- MeberService가 정확히 출력되었다.

 

 

AOP 적용 후 MemberService

- MemberService&&SpringCGLIB$$0으로 출력되었다. ( SpringCGLIB는 Proxy객체를 생성해주는 라이브러리이다.)

 

 

 

 

 

 

참고자료