springframework

AOP 의 @Before ,@AfterThrowing, @AfterReturning, @Around

Jungsoomin :) 2020. 9. 4. 23:45

aop에 대해 보강해보았던 점을 기록한다. 개인적으로 @Around 와 ProceedingJoinPoint, Signature 외에는 모르던 터라, 신비하고 기억해야겠다 싶어 타이핑하며 기억을 되새긴다.

 

execution명시자의 메서드 명과 파라미터 타입을 정확히 개시한 후, && 기호 이후 args 명시자의 속성 값으로 파라미터 명을 개시하면, advice 의 메서드에서 해당 매서드의 파라미터 값을 가져와 추적할 수 있다. 

@Before("execution(* me.soomin.service.SampleService*.doAdd(String, String)) && args(str1, str2)")
	public void logBeforeWithParam(String str1, String str2) {
		log.info("Str1 : " + str1);
		log.info("Str2 : " + str2);
	}

@AfterThrowing 은 Target의 PointCut에 명시된 joinPoint 실행 중에 예외가 터질 경우 작동하는데, 이때 throwing 속성값으로 exception을 지하여 터진 예외를 파라미터명으로 가져와 추적할 수 있다.

@AfterThrowing(pointcut = "execution(* me.soomin.service.SampleService*.*(..))", throwing = "exception")
	public void logException(Exception exception) {
		log.info("Exception : " + exception);
	}
INFO : me.soomin.aop.LogAdvice - Exception : java.lang.NumberFormatException: For input string: "aaa"

aop에서 찍어낸 기록에서 도 어디서 어떤 예외가 터졌는지 알 수 있다. (Log4j 사용)


@Around 에노테이션은 ProceedingJoinPoint 와 함께다닌다. .proceed()로 Target의 메서드를 실행하여 Object로 리턴값을 받아 리턴한다.

 AroundAdvice 라고 기억하는데, 이는 메서드 실행전후 예외발생을 뜻한다고 기억하고있다.

@Around("execution( * me.soomin.service.SampleService*.*(..) )")
	public Object logTime(ProceedingJoinPoint point) {
		long start = System.currentTimeMillis();

		log.info("Target : " + point.getTarget());
		log.info("Param : " + Arrays.toString(point.getArgs()));
        
        Signature sig = point.getSignature();

		log.info("Sig getName : " + sig.getName());
		log.info("Sig getLongString : " + sig.toLongString());
		log.info("Sig getShortString : " + sig.toShortString());

		Object result = null;

		try {
			result = point.proceed();
		} catch (Throwable e) {
			e.printStackTrace();
		}
		long end = System.currentTimeMillis();

		log.info("Time : " + (end - start));

		return result;
	}
Target : me.soomin.service.SampleServiceImpl@20ca951f
INFO : me.soomin.aop.LogAdvice - Param : [aaa, 123]
INFO : me.soomin.aop.LogAdvice - Sig getName : doAdd
INFO : me.soomin.aop.LogAdvice - Sig getLongString : public abstract java.lang.Integer me.soomin.service.SampleService.doAdd(java.lang.String,java.lang.String)
INFO : me.soomin.aop.LogAdvice - Sig getShortString : SampleService.doAdd(..)

콘솔내용 ( •_•)>⌐■-■


  1. 어느 객체가 Target의 메서드를 호출

  2. Proxy가 가로채어 @Aspect 클래스 객체의 메서드를 실행(Advice)

  3. Advice의 메서드에서 ProceedingJoinPoint 의 proceed 메서드를 호출

  4. ProceedingJoinPoint가 Target의 메서드를 실행하고 리턴 값을 받음

  5. Advice의 메서드가 리턴 값을 받고 Advice 로직 을 종료하고 리턴

  6. Proxy가 리턴값을 받아 호출 객체에게 리턴

으로 종료되는 것으로 알고 있다.

 

이로 인해, 거슬러올라가는 과정을 거친다는 흐름으로 , Advice가 하나의 메서드에 공통적으로 PointCut을 가질때에 역순으로 결과 값이 찍히는 경우가 있다. 이를 제어하기 위해 @Order에노테이션을 사용한다고 기억하고 있다.

 


  • ProceedingJoinPoint 의 메서드 

  • Signature getSignature() : 호출메서드의 정보를 가진 객체리턴

  • Object getTarget() : 대상 객체를 리턴

  • Object[] getArgs() : 호출 메서드의 파라미터목록을 리턴 ( 실제로 들어오는 파라미터)

  • org.aspectj.lang.Signature 의 메서드

  • String getName() : 호출 메서드의 이름을 리턴

  • String toLongString() : 호출되는 메서드를 완전히 표현한 문장을 리턴 / 리턴타입 파라미터 타입등이 모두 기재

  • String toShortString() : 호출되는 메서드의 축약한 문장을 리턴 / 메서드의 이름.

일단 기억은 여기까지이다.