[37일차] AOP, Advice, PointCut

유태형·2022년 6월 20일
0

코드스테이츠

목록 보기
37/77

오늘의 목표

  1. AOP
  2. Advice
  3. PointCut



내용

AOP

  • 애스팩트(Aspect)

부가 기능과 해당 부가 기능을 어디에 적용할지 정의한 것입니다. 합해서 하나의 모듈로 만든 것입니다.

애플리케이션에서 공통적으로 사용되는 공통기능들 하나의 기능으로 보는것이 아닌, 횡단 관심사(cross-cutting concerns)관점으로 보는 것입니다.

  • 핵심 기능(Core concerns) : 업무 로직을 포함하는 기능입니다.
  • 부가 기능(Cross-Cutting Concerns) : 핵심 기능을 도와주는 부가적인 기능입니다.
    ex)로깅,보안,트랜잭션
  • Aspect : 부가 기능을 정의한 어드바이스(Advice)와 어드바이스를 어디에 적용할지 결정하는 포인트컷(PointCut)을 합친 개념입니다.(Aspect = Advice + PointCut)

객체 지향 프로그래밍은 동작보단 데이터와 동작을 묶은 객체를 중심으로 프로그래밍을 합니다. 재사용을 적극적으로 활용할 수 있는것이 큰 장점이지만 관심사 분리(Soc)의 디자인 원칙을 준수해야 합니다.(관심사 분리는 모듈화의 핵심)

AOP는 회단 관심사 코드를 깔끔하게 분리하고 비즈니스 코드에 적용하기 위해 등장하였습니다.



AOP란?

AOP(Aspect-Oriented Programming)는 기존과 다른 프로그램 구조 사고 방식을 제공함으로써 객체 지향 프로그래밍의 부족한 부분을 보완합니다.
OOP의 모듈화의 핵심 단위는 클래스이고, AOP의 모듈화의 핵심 단위는 관점입니다. Aspect는 여러 유형과 객체 간에 발생하는 문제의 모듈화를 가능하게 합니다.

애플리케이션 로직은 핵심 기능부가 기능으로 나뉠 수 있습니다.

AOP는 부가 기능(Cross-Cutting Concerns)을 지원하기 위해 사용됩니다.

  • 핵심 기능을 보조하기 위해 제공되는 기능입니다.
  • 로그 추적 로직, 보안, 트랜잭션 기능 등이 있습니다.
  • 단독으로 사용되지 않고 핵심 기능과 함께 사용됩니다.
  • 부가 기능이 필요한 경우엔 핵심 기능 객체 안에 들어가서 로직을 완성합니다.
  • 서비스를 실행하면 핵심 기능과 부가 기능이 함께 실행됩니다.
  • 부가 기능은 여러 클래스에 함께 사용됩니다.(횡단 관심사)


애스팩트(Aspect)

  • 여러 객체에 공통으로 적용되는 기능을 말합니다.
  • 어드바이스 + 포인트컷을 모듈화하여 애플리케이션에 포함되는 회단 기능입니다.
  • 여러 어드바이스와 포인트컷이 함께 존재합니다.


조인 포인트(Join Point)

매서드 실행전을 Before 메서드 실행 후를 After로 포인트를 구분하여 어드바이스가 적용될 조인포인트라고 부릅니다.

  • 클래스 초기화, 객체 인스턴스화, 메서드 호출, 필드 접근, 예외 발생과 같은 애플리케이션 실행 흐름에서의 특정 포인트를 의미합니다.
  • 애플리케이션에 새로운 동작을 추가하기 위해 조인포인트에 관심 코드를 추가할 수 있습니다.
  • 횡단 관심은 조인포인트 전/후에 AOP에 의해 자동으로 추가됩니다.
  • 스프링 AOP는 프록시 방식을 사용하므로 조인 포인트는 항상 메서드 실행 지점으로 제한됩니다.
  • 어드바이스 적용이 필요한 곳은 애플리케이션 내에 메서드를 갖습니다.


어드바이스(Advice)

  • 조인 포인트에서 수행되는 코드입니다.
  • 시스템 전체 애스팩트에 API 호출으 제공합니다.
  • 부가 기능에 해당됩니다.


포인트컷(PointCut)

  • 조인 포인트 중에서 어드바이스가 적용될 위치를 지정하는 기능입니다.
  • AspectJ 표현식을 사용해서 지정합니다.


위빙(Weaving)

  • 어드바이스를 적용하는 것입니다.
  • 핵심 기능 코드에 영향을 주지 않고 부가 기능을 추가할 수 있습니다.
  • AOP 적용을 위해 애스펙트 객체에 연결한 상태입니다.


프록시(Proxy)

  • AOP 기능을 구현하기 위해 만든 프록시 객체입니다.
  • 스프링에서 AOP 프록시는 JDK 동적 프록시 또는 CGLIB 프록시입니다.


타겟(Target)

  • 핵심 기능을 담고 있는 모듈, 타겟은 부가기능을 부여할 대상
  • Advice를 받는 객체, 포인트컷으로 결정됩니다.


어드바이저(Advisor)

  • 하나의 어드바이스와 하나의 포인트 컷으로 구성됩니다.



어드바이스(Advice)

부가 기능으로 써, Aspect를 언제 핵심 코드에 적용할지 정의합니다.



순서

어드바이스는 기본으로는 순서를 보장하지 않습니다.

  • @Aspect 적용 단위로 org.springframework.core.annotation.@Order애너테이션을 적용하여 순서를 지정할 수 있습니다. 어드바이스 단위가 아니라 클래스 단위이며 하나의 애스팩트에 여러 어드바이스가 존재하면 순서를 보장 받을 수 없습니다.
  • 애스팩트를 별도의 클래스로 분리해야 합니다.


Before

조인 포인트 실행 이전에 실행됩니다. 타겟 메서드가 실행되기 전에 처리해야할 필요가 있는 부가 기능을 공통으로 실행합니다. @Before 어드바이스를 구현한 메서드는 일반적으로 리턴타입이 void입니다.(리턴 타입이 있더라도 아무 영향이 없습니다.)단, 해당 어드바이스에서 예외를 발생시킬 경우 대상 객체의 메서드가 호출되지 않으므로 주의해야합니다.

@Before("hello.app.order.aop.Pointcuts.orderAndService()")
public void doBefore(JoinPoint joinPoint){
	log.info("[before] {}", joinPoint.getSignature());
}

메서드 종료 시 자동으로 다음 타겟이 호출되며 예외 발생시 다음 코드는 호출되지 않습니다.



After returning

조인 포인트가 정상 완료후 실행합니다. 메서드가 예외 없이 실행된 이후에 공통 기능을 실행합니다.

@AfterThrowing(value = "hello.app.order.aop.Pointcuts.orderAndService()", returning = "result")
public void doReturn(JoinPoint joinPoint, Object result){
	log.info("[return] {} return={}",joinPoint.getSignature(), result);
}
  • returning 속성에 사용된 이름은 어드바이스 메서드의 매개변수와 일치해야 합니다.
  • returning절에 지정된 타입의 값을 반환하는 메서드만 대상을 실행합니다.


After throwing

메서드가 예외를 일으키는 경우에 실행합니다.

@AfterThrowing(value = "hello.aop.order.aop.Pointcuts.orderAndService()", throwing="ex")
public void doThrowing(JoinPoint joinPoint, Exception ex){
	log.info("[ex] {} message={}",joinPoint.getSignature(),ex.getMessage());
}
  • throwing 속성에 사용된 이름은 어드바이스 메서드의 매개변수 이름과 일치해야 합니다.
  • throwing 절에 지정된 타입과 맞은 예외를 대상으로 실행합니다.


After

조인 포인트가 정상적으로 끝났든 비정상적으로 예외를 발생시키든 상관없이 실행합니다.(finally)
메서드 실행후 공통 기능을 실행하므로, 보통 리소스를 해제하는데 사용합니다.



Arround

매서드 호출 전/후에 수행하는 어드바이스 입니다. 메서드 실행 전/후, 예외발생 시점에 공통 기능을 실행합니다.

@Arround("AspectJ 표현식")
public Ojbect doArround(ProceedingJoinPoint pjp) throws Throwable{
	Object result = pjp.proceed();
    return result;
}
  • @Arround어드바이스의 첫 번째 파라미터는 ProceedingJoinPoint를 사용해야 합니다.
  • ProceedingJoinPoint.proceed()를 통해 대상을 실행할 수 있습니다.

@Arround만 있어도 모든 부가 기능 수행이 가능하지만, 고려사항이 있을 때 정상적으로 작동 되지 않을 수도 있으므로 실수나, 에러르 방지하기 위해 어드바이스를 하나가 아닌 여러개로 상황에 맞게 사용해야 합니다.




PointCut

포인트 컷은 관심 조인 포인트를 결정하므로 어드바이스가 실행되는 시기를 제어할 수 있습니다. AspectJ는 포인트컷을 편리하게 효현하기 위한 특별한 표현식을 제공합니다.
@Pointcut("execution(* hello.aop.order..*(..))")

@Pointcut("execution(* transfer(..))")
public void anyOldTransfer(){}

포인트컷 표현식을 AspectJ가 제공하는 표현식으로 표현합니다.



지시자

포인트컷 표현식은 포인트컷 지시자(PointCut Designator,PCD)로 시작합니다.

포인트컷설명
execution메서드 실행 조인 포인트를 매칭한다.
within특정 타입 내의 조인 포인트를 매칭한다.
args인자가 주어진 타입의 인스턴스인 조인 포인트
this스프링 빈 객체를 대상으로 하는 조인 포인트
targetTarget객체를 대상으로 하는 조인 포인트
@target실행 객체의 클래스에 주어진 타입의 에너테이션이 있는 조인 포인트
@within주어진 애너테이션ㅇ ㅣ있는 타입 조인 포인트
@annotation메서드가 주어진 에너테이션을 가지고 있는 조인 포인트를 매칭
@args전달된 실제 인수의 런타임 타입이 주어진 타입의 에너테이션을 가지는 조이는 포인트
bean빈의 이름으로 포인트컷을 지정

exection을 가장 많이 사용합니다.

포인트컷 표현식은 %% || !를 결합하여 사용할 수 있습니다.



표현식들

모든 공개 메서드 실행

execution(public * *(..))

set 다음 이름으로 시작하는 모든 메서드 실행

excution(* set*(..))

Account 인터페이스에 의해 정의된 모든 메서드의 실행

execution(* com.aop.service.Account.*(..))

service 패키지에 정의된 메서드 실행

execution(* com.aop.service.*.*(..))

service 패키지 또는 해당 하위 패키 중 하나에 정의된 메서드 실행

execution(* com.aop.service..*.*(..))

service 패키지 내의 모든 조인 포인트

within(com.aop.service.*)

service 패키지 또는 하위패키지 중 하나 내의 모든 조인 포인트

within(com.aop.service..*)

Account 인터페이스를 구현하는 모든 조인 포인트

this(com.aop.service.Account)

대상 객체에 @Transactional 애너테이션이 있는 모든 조인 포인트

@target(org.springframework.transaction.annotation.Transactional)

실행 메서드에 @Transactional 애너테이션이 있는 조인 포인트

@annotation(org.springframework.transaction.annotation.Transactional)

단일 매개변수를 사용하고 전달된 인수의 런타임 유형 @Classified 애너테이션을 갖는 조인 포인트

@args(com.aop.repo.Classified)

trade라는 이름을 가진 스프링 빈의 모든 조인 포인트

bean(trade)

이름이 service로 끝나는 스프링 빈의 모든 조인 포인트

bean(*service)



후기

DI까지만 해도 이해가 많이 되었지만 AOP부터는 이해가 잘 안되기 시작해서 조금 걱정이 됩니다. 앞으로 더 이해하기 어려운 내용들이 나올 것 같아서 더 인터넷 강의도 보고 검색도 자주하고 해야할 것 같습니다.




GitHub

없음!

profile
오늘도 내일도 화이팅!

1개의 댓글

comment-user-thumbnail
2023년 11월 29일

정리가 넘 좋슴다~

답글 달기