728x90
반응형
Advice 종류
- @Around
- 메서드 호출 전후에 수행
- 가장 강력한 어드바이스
- join point 실행 여부 선택
- 반환 값 변환
- 예외 변환 등 가능
- @Before
- join point 실행 이전에 실행
- @AfterReturning
- join point가 정상 완료 후 실행
- @AfterThrowing
- 메서드가 예외를 던지는 경우 실행
- @After
- join point가 정상 또는 예외에 관계 없이 실행 (finally)
@Before("hello.aop.order.aop.Pointcuts.orderAndService()")
public void doBefore(JoinPoint joinPoint) {
log.info("[before] {}", joinPoint.getSignature());
}
@AfterReturning(value = "hello.aop.order.aop.Pointcuts.orderAndService()", returning = "result")
public void doReturn (JoinPoint joinPoint, Object result) {
log.info("[return] {} return={}", joinPoint.getSignature(), result);
}
@AfterThrowing(value = "hello.aop.order.aop.Pointcuts.orderAndService()", throwing = "ex")
public void doThrow(JoinPoint joinPoint, Exception ex) {
log.info("[ex] {} message={}", joinPoint.getSignature(), ex); // 자동으로 throw e 해줌
}
@After(value = "hello.aop.order.aop.Pointcuts.orderAndService()")
public void doAfter(JoinPoint joinPoint) {
log.info("[after] {}", joinPoint.getSignature());
}
- @Around 어드바이스만 사용해도 필요한 기능 모두 수행 가능
참고 정보 획득
- 모든 어드바이스는 JoinPoint를 첫번째 파라미터에 사용할 수 있다. (생략 가능)
- 단, @Around는 ProceedingJoinPoint를 사용해야 한다.
- ProceedingJoinPoint는 JoinPoint의 하위 타입
ProceedingJoinPoint 인터페이스 주요 기능
- proceed(): 다음 어드바이스나 타켓 호출
- Around는 다음을 내가 직접 호출해줘야함
JoinPoint 인터페이스 주요 기능
- getArgs() : 메서드 인수를 반환
- getThis() : 프록시 객체를 반환
- getTarget() : 대상 객체를 반환
- getSignature() : 조언되는 메서드에 대한 설명을 반환
- toString() : 조언되는 방법에 대한 유용한 설명을 인쇄
@Before
- @Before는 @Around와 다르게 작업 흐름을 변경할 수 없다.
- @Around는 ProceedingJoinPoint.proceed() 를 호출해야 다음 대상이 호출된다.
- 만약 호출하지 않으면 다음 대상이 호출되지 않는다.
- @Before는 ProceedingJoinPointer.proceed() 자체를 사용하지 않는다.
- 메서드 종료시 자동으로 다음 타켓이 호출된다.
- 물론 예외가 발생하면 다음 코드 호출되지 않는다.
@AfterReturning
- returning 속성에 사용된 이름은 어드바이스 메서드의 매개변수 이름과 일치해야 함
- returning 절에 지정된 타입의 값을 반환하는 메서드만 대상으로 실행함
- 부모 타입을 지정하면 모든 자식 타입이 인정된다.
- 반환값이 void일 경우에 매개변수 타입을 String으로 둔다면 값을 받아오지 못해 실행하지 않는다.
- @Around와 다르게 반환되는 객체를 변경할 수는 없다.
- 반환 객체를 조작할 수는 있다 → 예를 들어 setter 호출
- 반환 객체를 변경하려면 @Around를 사용해야함
@AfterThrowing
- throwing 속성에 사용된 이름은 어드바이스 메서드 매개변수 이름과 일치해야 함
- throwing 절에 지정된 타입과 맞는 예외를 대상으로 실행함
- 부모 타입을 지정하면 모든 자식 타입이 인정된다.
@After
- 메서드 실행 종료되면 실행됨 (finally)
- 정상 및 예외 반환 조건 모두 처리
- 일반적으로 리소스 해제할 때 사용
@Around
- 메서드 실행의 주변에서 실행
- 메서드 실행 전후에 작업 수행
- 가장 강력한 어드바이스
- 조인 포인트 실행 여부 선택: joinpoint.proceed() 호출 여부 선택
- 전달값 변환: joinPoint.proceed(args[])
- 반환 값 변환
- 예외 변환
- 트랜잭션처럼 try~catch~finally 모두 들어가는 구문 처리 가능
- 어드바이스 첫 번째 파라미터 ProceedingJoinPoint사용
- proceed()를 통해 대상을 실행
- proceed() 여러번 실행할 수 있음 (재시도)
- 스프링은 5.2.7 버전부터 동일한 @Aspect 안에서 동일한 조인포인트의 우선순위를 정했다.
- 실행 순서: @Around , @Before , @After , @AfterReturning , @AfterThrowing
어드바이스가 적용되는 순서는 이렇게 적용되지만, 호출 순서와 리턴 순서는 반대라는 점을 알아두자.
물론 @Aspect 안에 동일한 종류의 어드바이스가 2개 있으면 순서가 보장되지 않는다. 이 경우 앞서 배운 것 처럼 @Aspect 를 분리하고 @Order 를 적용하자.
@Around 외 다른 어드바이스가 존재하는 이유
@Around("hello.aop.order.aop.Pointcuts.orderAndService()")
public void doBefore(ProceedingJoinPoint joinPoint) {
log.info("[before] {}", joinPoint.getSignature());
}
- 문제점: 타겟을 호출하지 않는다. 부가 기능만 수행하고 끝내버린다
- @Around는 항상 joinPoint.proceed()를 호출해야한다.
- 만약 실수로 호출하지 않으면 치명적인 버그가 발생한다.
- @Before 는 joinPoint.proceed() 를 호출하는 고민을 하지 않아도 된다.
- @Around가 가장 넓은 기능을 제공하는 것은 맞지만 실수할 가능성이 있다.
- 반면에 @Before, @After 같은 어드바이스는 기능은 적지만 실수할 가능성이 낮고 코드도 단순하다.
- 이 코드를 작성한 의도가 명확하게 드러난다는 점이 중요하다!
좋은 설계는 제약이 있는 것이다!
- 제약이 있어야 역할이 명확해진다.
- 코드의 의도를 파악하기 쉬워진다.
728x90
반응형
댓글