Spring TIL - Spring AOP이용 Logger 테스트

Jieun·2023년 5월 12일
0

📝 Spring AOP 개념정리 및 어노테이션 별 Logger테스트
#230512

💻작업파일

[board]-[common]-[aop]-TestAspect
[board]-[common]-[aop]-CommonPointcut
[board]-[common]-[aop]-BeforeAspect
[board]-[common]-[aop]-AfterAspect
[board]-[common]-[aop]-AfterReturningAspect
[board]-[common]-[aop]-AfterThrowingAspect
[board]-[common]-[aop]-AroundAspect

@Component

런타임시 필요한 코드를 알아서 참여시킬 수 있도록 bean 등록

@Aspect

  • 공통 관심사(특정 흐름 사이에 끼여서 수행할 코드)가 작성된 클래스임을 명시

  • 해당 어노테이션이 작성된 클래스에서는
    advice(끼여들어서 수행할 메서드), pointcut(advice가 끼여들어서 수행될 부분) 이 작성되어 있어야한다.

💻 joinpoint : advice가 적용될 수 있는 지점
💻 pointcut : joinpoint 중에서 실제로 advice를 적용할 지점 선택

@pointcut 작성방법

@Pointcut("execution([접근제한자] 반환형 패키지+클래스명.메서드명([매개변수]))")

* : 모든 | 아무 값
.. : 하위 | 아래 (하위 패키지) | 0개 이상의 매개변수

package edu.kh.comm.common.aop;

import org.aspectj.lang.annotation.Pointcut;

public class CommonPointcut {
	
// 회원 서비스용 Pointcut
@Pointcut("execution(* edu.kh.comm.member..*Impl.*(..))")
public void memberPointcut() {} 

// 모든 ServiceImpl 클래스용 Pointcut
@Pointcut("execution(* edu.kh.comm..*Impl.*(..))")
public void implPointcut() {}
	
}

JoinPoint 인터페이스

advice가 적용되는 Target Object (ServiceImpl)의
정보, 전달되는 매개변수, 메서드, 반환값, 예외 등 얻을 수 있는 메서드를 제공

❗주의사항 : JoinPoint 인터페이스는 항상 첫 번째 매개변수로 작성되어야 한다!


@Before("CommonPointcut.implPointcut()")
	public void serviceStart(JoinPoint jp) {

//jp.getTarget() : aop가 적용된 객체 (각종 ServiceImpl)	
String className = jp.getTarget().getClass().getSimpleName();
	
// jp.getSignature() : 수행되는 메서드 정보
String methodName = jp.getSignature().getName();
	
// jp.getArgs() : 메서드 호출 시 전달된 매개변수
String param = Arrays.toString(jp.getArgs() );

str += "Start : " + className + " - " + methodName + "\n";
// Start : MemberServiceImpl - login
		
str += "Parameter : " + param + "\n";

@Before

타겟 객체의 메소드가 실행 되기 전에 호출되는 어드바이스

@After

타겟 객체의 메소드 호출 전과 후에 실행 될 코드를 구현할 어드바이스


@AfterReturning

기존 @After + 반환값 얻어오기 기능

@Order(숫자)

css의 z-index 와 같은거
advice 실행 순서, 클 수록 먼저 시작

@Component
@Aspect
@Order(5)
public class AfterReturningAspect {

	private Logger logger = LoggerFactory.getLogger(AfterReturningAspect.class);
	
	@AfterReturning(pointcut = "CommonPointcut.implPointcut()" , returning = "returnObj")
	public void serviceReturnValue(JoinPoint jp, Object returnObj) {
		
		logger.info("Return Value : " + returnObj);
	}
}

@AfterThrowing

기존 @After + 던져지는 예외 얻어오기 기능

@Component
@Aspect
public class AfterThrowingAspect {
	private Logger logger = LoggerFactory.getLogger(AfterThrowingAspect.class);
    
	
	@AfterThrowing(pointcut = "CommonPointcut.implPointcut()" , throwing = "exceptionObj")
	public void serviceReturnValue(JoinPoint jp, Exception exceptionObj) {
		
		String str = "<<exception>> : " + exceptionObj.getStackTrace()[0];
		
		str += " - " + exceptionObj.getMessage()  + "\n";
		
		logger.error(str);
		
	}
}

@Around

전처리(@Before)와 후처리(@After)를 한번에 작성 가능한 advice

@Component
@Aspect
@Order(4) 
public class AroundAspect {
	
	private Logger logger = LoggerFactory.getLogger(AroundAspect.class);

    @Around("CommonPointcut.implPointcut()")
    public Object runningTime(ProceedingJoinPoint jp) throws Throwable {
		
        // proceed() 메소드 호출 전  : @Before advice 작성
        // proceed() 메소드 호출 후  : @After advice 작성
        // 메소드 마지막에 proceed()의 반환값을 리턴해야함


        // System.currentTimeMillis() :
        // 1970/01/01 오전 9시 (한국 OS 기준) 부터
        // 지금까지 지난 시간을 ms 단위로 나타낸 값	
        long startMs = System.currentTimeMillis();   // before(전처리)

        Object obj = jp.proceed(); // 전/후 처리를 나누는 기준      

        long endMs = System.currentTimeMillis();   // after (후처리)


        logger.info("Running Time : " + (endMs - startMs) + "ms");


        return obj;
        // proceed()반환값 리턴해주기
	
	}

}
profile
👩‍💼👩‍💼➡️➡️➡️👩‍💻👩‍💻 생산자의 삶을 살기 위해 개발공부중

0개의 댓글