AOP - advice의 타입

박준서·2024년 10월 17일
5

Web

목록 보기
12/16
post-thumbnail

advice는 실행되는 시점에 따라 여러가지 타입으로 작성할 수 있다.

advice 타입

  • advice가 동작하기 위해서는 어떤 시점에 advice를 실행할 것 인가를 결정해야 한다. Spring에서는 총 5가지 annotation으로 이 시점을 설정할 수 있다.
애너테이션설명
@Before타겟 메서드 호출 전 advice 실행
@AfterReturning타겟 메서드가 정상 종료 (return) 후 advice 실행
@AfterThrowing타겟 메서드에서 예외가 던져졌을 때 (throws XXException) advice 실행
@After타겟 메서드 성공 여부 (return or throws)와 무관하게 언제나 advice 실행
@Aroundadvice 내부에서 타겟 메서드 호출 (타겟 메서드의 모든 것을 제어 가능)

@Before

  • @Before가 선언된 advice는 target 메서드가 실행되기 전에 호출되며 advice에서 예외가 발생하면 아예 target이 호출되지 못한다.
  • @Before에서는 타겟 호출 전에 전달되는 argument에 대한 조작이 가능하다.
    • 단, 완전히 대체 할 수는 없으며 객체의 경우 그 속성의 변경은 가능하다
  • pointcut에 args(변수명)을 사용하면 바로 파라미터로 처리할 수 있다.
@Before("execution(com.practice.aop.dto.User com.practice..regist(com.practice.aop.dto.User)) && args(user)")
public void before(JoinPoint jp, User user) {
	// user = new User("hi", "1234"); // 새로운 값으로는 대체 불가
	user.setPass("암호화_" + user.getPass());
}
  • advice 내에서 전달된 argument인 user을 수정하고 있는데 주석처럼 새로운 user 할당은 불가능 하다.

@AfterReturning

  • 타겟 메서드가 정상적인 종료(return)된 경우에 동작한다.
  • target에서 예외가 발생하는 경우에는 동작하지 않는다. 따라서, try~catch~finally에서 try 정도에 해당한다
  • return 받은 값을 수정할 수 있는데, 전달 받은 객체의 내용을 수정 할 수 있으나 완전히 새로운 값을 할당할 수는 없다.
  • 속성으로 pointcut을 받는 valuereturn 값을 받을 변수 명을 의미하는 returning 속성을 갖는다.
  • advice 작성 시는 returning을 메서드의 파라미터로 선언해주어야 한다.
@AfterReturning(value = "userPointcut()", returning = "user")
public void maskingPW(JoinPoint jp, User user) {
	user.setPass("*"); // return 값 조작
}

@AfterThrowing

  • 타겟의 메서드가 예외를 던졌을 때만 동작
  • 정상적으로 값을 반환 했을 때에는 동작하지 않는다
  • try~catch~finally에서 catch 정도에 해당한다
  • 속성으로 pointcut을 받는 value와 전달받은 예외 객체의 이름을 의미하는 throwing 속성을 갖는다.
  • 이 애너테이션과 연결되는 메서드는 동일한 이름의 파라미터가 선언되어야 하며 파라미터의 타입은 타겟에서 전달되는 예외와 같거나 부모 타입으로 선언되어야 한다.
@AfterThrowing(value = "userPointcut()", throwing = "e")
public void getException(JoinPoint jp, RuntimeException e) {
	log.debug("에러 발생");
}

@After

  • try~catch~finally에서 finally 정도에 해당한다.
  • 타겟의 예외 상황과 상관 없이 언제나 실행된다.
  • pointcut을 받는 value 속성을 갖는다.
@After("bean(myService)")
public void endlogging(JoinPoint jp) {
	log.debug("끝");
}

@Around

  • 위의 다른 advice들과 달리 타겟 메서드의 호출을 advice 내부에서 직접 수행한다.
  • 따라서 이전 advice 들과 달리 파라미터, 리턴 값에 대한 완전한 대체 및 예외 처리가 가능하다. 이는 타겟 메서드의 실행 자체를 제어할 수 있다는 뜻이기 때문이다.
@Around("execution(* com.example..*(..))")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
    Object[] args = joinPoint.getArgs();  // 파라미터를 가져옴
    args[0] = "Modified Value";  // 파라미터 수정
    Object result = joinPoint.proceed(args);  // 수정된 파라미터로 메서드 호출
    return result;
}
  • @Around advice 내에서 target 메서드 호출을 위해 이제까지와는 달리 JoinPoint를 상속받은 ProceedingJoinPoint를 파라미터로 갖는다.
  • advice 메서드의 리턴 타입은 타겟 메서드의 리턴타입과 같아야 한다.
  • ProceedingJoinPoint는 JoinPoint를 상속받았기 때문에 getArgs()를 통해 타겟에 전달되는 파라미터들에 접근, 파라미터 조작이 가능하다.
  • target에서 전파한 예외는 proceed()가 받아서 throws 한다. 호출자에게까지 예외를 전달해줘야 하기 때문에 당연히 throws 해줘야 한다.
  • 호출 결과를 내부적으로 리턴해주기 때문에 필요에 따라 결과의 조작도 가능하다.
    @Around("execution(* com.example.service.MyService.*(..))")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        // 메서드 실행 전
        System.out.println("메서드 실행 전: " + joinPoint.getSignature());
        
        // 메서드 파라미터 로그 출력
        Object[] args = joinPoint.getArgs();
        for (Object arg : args) {
            System.out.println("파라미터 값: " + arg);
        }

        // 타겟 메서드 실행
        Object result = joinPoint.proceed();

        // 메서드 실행 후
        System.out.println("메서드 실행 후: " + joinPoint.getSignature());

        // 리턴 값을 변경 (예: 원래 결과에 " - modified" 추가)
        if (result instanceof String) {
            result = result + " - modified";
        }

        // 수정된 리턴 값을 반환
        return result;
    }
}
  • 메서드 실행 전에 joinPoint.getSignature()를 사용해 호출되는 메서드의 정보를 로그로 출력한다.
  • joinPoint.getArgs()로 메서드의 파라미터 값을 가져와서 로그로 출력한다.
  • joinPoint.proceed()가 호출되면, 실제 타겟 메서드가 실행된다.
  • 메서드 실행 후 로깅:
    • 메서드가 실행된 후 다시 메서드 정보를 로그로 출력한다.
  • 리턴 값 수정:
    • 타겟 메서드가 반환한 값을 result에 저장한 후, 그 값이 String 타입이면 " - modified"라는 문자열을 추가로 붙인다.
    • 수정된 값을 최종적으로 반환한다.
profile
Back-End Developer

0개의 댓글

관련 채용 정보