ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • AOP란?
    Spring/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객체를 생성해주는 라이브러리이다.)

     

     

     

     

     

     

    참고자료

     

Designed by Tistory.