스프링 AOP

이성준·2022년 4월 23일
0

Spring

목록 보기
7/11

AOP 란?

핵심기능과 부가기능

  • 핵심기능 : 해당 객체가 제공하는 고유의 기능
  • 부가기능 : 핵심 기능을 보조하기 위해 제공하는 기능

우리들이 어떤 기능을 구현할 때 거기서만 사용하는 핵심기능이 있고 로깅작업 같은 공통으로 해야하는 기능들이 있다. 핵심기능에 이런 공통기능들을 일일히 붙히면 귀찮고 만약 수정을 해야한다고치면 하나씩 다 찾아서 수정을 해야합니다. 그래서 여러군데에서 사용하는 공통기능들을 떼어내서 분리하고, 어떤 로직을 기준으로 핵심적인 관점, 부가적인 관점으로 나누어 모듈화 하는 기술을 AOP라고 합니다.

용어

  • Joinpoint : Advice를 적용 가능한 지점을 의미합니다. 메서드 호출, 필드 값 변경 등이 Joinpoint에 해당합니다.

  • Pointcut : Joinpoint의 부분 집합으로서 실제로 Advice가 적용되는 Joinpoint를 나타냅니다.

  • Advice : 부가기능 그 자체, 언제 공통 기능을 적용할 지를 정의할 수도 있습니다.

  • Weaving : Advice를 핵심 로직 코드에 적용하는 것을 weaving이라고 한다. aspectj 프레임워크는 런타임과 로드타임에 소스코드를 박아버리지만 스프링 aop는 프록시 방식으로 동작합니다.

  • Aspect : PointCut+Advice, 부가기능을 어디에 적용할것인가를 모듈화 한것

  • Advisor : PointCut+Advice, Aspect를 스프링에서 이렇게 부르는거 같다?

구현

결국 어드바이져를 만들면 됩니다.

@Slf4j
   1. @Aspect
    public class AspectV1 {
	//hello.aop.order 패키지와 하위 패키지
   2. @Around(3."execution(* hello.aop.order..*(..))")
	public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable {
	log.info("[log] {}", joinPoint.getSignature()); //join point 시그니처
            return joinPoint.proceed();
     }
}

1. Advisor로 만들꺼라는걸 스프링에게 알려주기

@Aspect

Advisor로 만들고싶은 객체에 @Aspect를 사용해줍니다.

@Aspect : 스프링에서 편리하게 Advisor를 생성해주는 어노테이션
원리 1. 스프링은 애플리케이션 로딩 시점에 자동 프록시 생성기를 빈으로 등록하는데
이 자동 프록시 생성기가 스프링 컨테이너 내 @Aspect 어노테이션 붙은 스프링 빈 모두 조회하고
@Aspect 어드바이저 빌더를 통해 Advisor를 생성하고
생성한 Advisor를 @Aspect 어드바이저 빌더 내부에 캐시합니다.
만약 캐시에 어드바이저가 이미 만들어져 있는 경우 캐시에 저장된 어드바이저를 반환합니다.

2. Advice 만들기

종류

5가지 어드바이스 종류가 있는데 얘네들은 어느 시점에 advice를 실행해줄지 결정해줍니다.

추가정보

@Before : ProceedingJoinPoint.proceed()를 사용하지 않기 때문에 메소드 종료시 자동으로 다음 타겟을 호출합니다.

@AfterReturning : returning속성으로 반환객체를 받을수있습니다

@AfterThrowing : throwing속성으로 예외를 받을수 있습니다.

@Around : proceed()로 여러번 실행할수도 있습니다.

3. PointCut 만들기

이제는 PointCut을 설정해주어야 하는데 스프링은 AspectJ에서 만든 포인트컷표현식을 확장시켜서 사용합니다.
그리고 이것을 포인트컷 지시자라고 부릅니다.

표현식문법

@excecution : 메소드 실행 조인 포인트를 매칭합니다.

?표는 생략이 가능하다는 뜻
리플렉션으로 메소드의 풀 시그니쳐를 문자열로 비교합니다.

  • 접근제어자
    public,private,protected 등 접근 제어자가 올수 있습니다. 생략이 가능합니다.
  • 반환타입
    반드시 하나의 타입을 지정해야하고 *를 써서 모든 타입을 다 선택해도 됩니다.

  • 선언타입
    패키지와 타입이름을 포함한 클래스의 타입 패턴입니다. 주의사항이 있는데
    hello.aop.member 패키지가 있을때
    hello.. 면 hello패키지와 그 하위 패키지도 포함이고
    hello. 면 정확하게 hello 패키지만 나타내는 것입니다.

  • 메서드이름
    메서드이름을 적어주면 되고 모두 선택할려면 *를 넣습니다.

  • 파라미터
    파라미터의 타입을 ,로 구분하면서 순서대로 적으면됩니다. ex (int,int)
    파라미터가 없으면 ()를 넣으면되고, ex ()
    파라미터의 타입과 개수에 상관없이 모두 허용할려면 ex (..)
    뒷부분의 파라미터 조건만 생략할려면 ex (String ...)

  • 예외
    예외이름이고 생략이 가능합니다.

//hello.aop.member 패키지에 있음
public String MemberServiceImpl hello(String itemId){
//로직
}

에 적용하고싶으면

  • 가장 정확하게 매칭하는 방법
execution(public String hello.aop.member.MemberServiceImpl.hello(String))

접근제어자 = public
반환타입 = String
선언타입 = hello.aop.member.MemberServiceImpl
메서드이름 = hello
파라미터 = hello

  • 가장 생략해서 매칭하는 방법
execution(* *(..))

접근제어자 = 생략
반환타입 = 아무거나
선언타입 = 생략
메서드이름 = 아무거나
파라미터 = 아무거나

포인트컷 지시자

는 너무길어져서 다음 포스팅으로 넘기겠습니다

0개의 댓글