본문으로 바로가기

[SPRING] SPRING AOP

category SPRING/기본 상식 2021. 4. 14. 03:58

AOP (Aspect-Oriented Programming) : 관점 지향 프로그래밍

 

- 흩어진 Aspect들을 모아서 모듈화 하는 기법이다.

- 여러 오브젝트에 나타나는 "공통적인 부가 기능"을 모듈화하여 "재사용"하는 기법이다.

 

주로 어떤경우에 사용할까요?

 

- 모든 메소드의 호출 시간을 측정하고 싶다면?
- 공통 관심사항(cross-cutting-concern) vs 핵심 관심사항(core concern)
- 회원 가입 시간, 회원 조회 시간을 측정하고 싶다면?

 

코드의 중복 발생을 해결하기 위해 나온것이 AOP 입니다.

 

 

AOP는 어떻게 등록하나요?

 

1. 컴포넌트 스캔 (@Component)
2. 빈에 직접등록 (권장)

 

아래와 같이 셋팅합니다.

 

1. build.gradle에 의존성 추가

 

2. TimeTraceAop 만들기 (@Component 선언하면 3번 생략)

package hello.core.aop;

import org.springframework.stereotype.Component;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

//@Component 1번 방법
@Aspect
public class TimeTraceAop {
    @Around("execution(* hello.core..*(..))")
    public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        System.out.println("START: " + joinPoint.toString());
        try {
            return joinPoint.proceed();
        } finally {
            long finish = System.currentTimeMillis();
            long timeMs = finish - start;
            System.out.println("END: " + joinPoint.toString()+ " " + timeMs + "ms");
        }
    }
}

 

* @Around 어노테이션은 타겟 메서드를 감싸서 특정 Advice를 실행한다는 의미이다. 위 코드의 Advice는 타겟 메서드가 실행된 시간을 측정하기 위한 로직을 구현하였다. 추가적으로 execution(* hello.core..*(..))가 의미하는 바는 hello.core 아래의 패키지 경로의 객체의 모든 메서드에 이 Aspect를 적용하겠다는 의미다.

3. Bean 객체 등록

package hello.core;

import hello.core.aop.TimeTraceAop;
import hello.core.discount.DiscountPolicy;
import hello.core.discount.FixDiscountPolicy;
import hello.core.discount.RateDiscountPolicy;
import hello.core.member.MemberRepository;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import hello.core.member.MemoryMemberRepository;
import hello.core.order.OrderService;
import hello.core.order.OrderServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

// 구현 객체 생성 및 연결
@Configuration
public class AppConfig {

    // 생성자를 통해서 주입(연결) 즉, 인젝션 해준다. (DIP 완성)
    @Bean
    public MemberService memberService() {
        return new MemberServiceImpl(memberRepository());
    }

    @Bean
    public MemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }

    @Bean
    public OrderService orderService() {
        return new OrderServiceImpl(memberRepository(), discountPolicy());
    }

    @Bean
    public DiscountPolicy discountPolicy() {
        return new RateDiscountPolicy();
    }
    
    // AOP 적용
    @Bean
    public TimeTraceAop timeTraceAop() {
        return new TimeTraceAop();
    }

}

 

 

AOP 해결 및 장점 : 

 

- 회원가입, 회원 조회등 핵심 관심사항과 시간을 측정하는 공통 관심 사항을 분리한다.

- 시간을 측정하는 로직을 별도의 공통 로직으로 만들었다.

- 핵심 관심 사항을 깔끔하게 유지할 수 있다.

- 변경이 필요하면 이 로직만 변경하면 된다.

- 원하는 적용 대상을 선택할 수 있다.

 

AOP 적용 후 의존관계

 

AOP 적용 후 전체 그림

 

어떤 부가기능을? 언제? 사용할까요????

Advice : 어떤 부가기능을 언제 사용할지에 대한 정의

 

어디에? 

Joinpoint : 어드바이스가 적용될 수 있는 위치 (메서드 호출, 필드 값 변경)

 

- 메서드 호출할때  (스프링AOP는 프록시기반) 적용됨.
- 변수에 접근할 때
- 객체를 초기화할 때
- 객체에 접근할 때

 

그 이외 설명

Pointcut : Advice를 적용할 Joinpoint를 선별하는 작업

Tartget : 부가 기능이 적용될 대상 Aspect를 적용하는 곳

 

Aspect : 여러 객체에 적용되는 기능 (트랜잭션이나 보안에 사용 됨)

 

AOP는 어디에 사용될까요?

1. 성능 검사
2. 트랜잭션 처리
3. 로깅

 

이 밖에도 @Around 외에 타겟 메서드의 Aspect 실행 시점을 지정할 수 있는 어노테이션이 있다.

  • @Before (이전) : 어드바이스 타겟 메소드가 호출되기 전에 어드바이스 기능을 수행
  • @After (이후) : 타겟 메소드의 결과에 관계없이(즉 성공, 예외 관계없이) 타겟 메소드가 완료 되면 어드바이스 기능을 수행
  • @AfterReturning (정상적 반환 이후)타겟 메소드가 성공적으로 결과값을 반환 후에 어드바이스 기능을 수행
  • @AfterThrowing (예외 발생 이후) : 타겟 메소드가 수행 중 예외를 던지게 되면 어드바이스 기능을 수행
  • @Around (메소드 실행 전후) : 어드바이스가 타겟 메소드를 감싸서 타겟 메소드 호출전과 후에 어드바이스 기능을 수행


출처 : 김영한의 스프링

출처 : 최범균의 스프링
출처: https://engkimbs.tistory.com/746 [새로비]