본문 바로가기
Spring/Spring

day67)[AOP] - 횡단관심: 로깅 처리하기2

by code_learner 2022. 4. 5.

https://code-learning.tistory.com/109

 

day66) [AOP] - 로깅 처리하기1

[AOP] - 관점 지향 프로그래밍 (때가 되면 알아서 동작할 수 있게 만든다) - 공통로직을 분리하기 위해 공통 로직과 (횡단 관심) + 핵심로직 (비즈니스 메서드)로 나누어 처리한다. - 기능을 하

code-learning.tistory.com

앞서 했던 로깅처리는 어떤 핵심관심(비즈니스 메서드, CRID)이 실행되는지 알지 못한다.

어드바이스(횡단관심, 공통로직)를 효율적으로 사용하려면 핵심관심을 알아 활용해야한다.

-> JoinPoint(사용자측에서 사용하는 '모든 비즈니스 메서드') 인터페이스를 활용해보자.
++

-> xml로 aspect(결합)했던 로깅을 @(어노테이션)으로 변경해보자

 

[JoinPoint 인자]

기존의 인자를 받지 않았던 LogAdvice.java에서 JoinPoint 인터페이스를 인자로 받으면 어떤 핵심관심인지, 사용되는 인자가 무엇인지 알 수 있다.

더보기
   public void beforeLog(JoinPoint jp) {
      // jp -> 어떤 핵심관심이 호출되었는지에대한 정보가 담겨있음!
      String methodName=jp.getSignature().getName();
      System.out.println("호출된 핵심관심: "+methodName);
      Object[] args=jp.getArgs();
      System.out.println("사용된 인자");
      for(Object v:args) {
         System.out.println(v);
      }
   }

 

 

[Object returnObj]

시점이 AfterReturning일 때 사용가능하다. 핵심관심 수행 완료후 return(반환값)을 볼 수 있다.

public void arLog(JoinPoint jp,Object returnObj) {
		// Object returnObj : 바인드 변수 -> 컨테이너에게 설정을 해주어야한다!!!
		System.out.println("afterReturning 로그");
		String methodName=jp.getSignature().getName();
		System.out.println("호출된 핵심관심: "+methodName);
		System.out.println("반환값: "+returnObj);
		if(returnObj instanceof MemberVO) { // 캐스팅 가능여부를 확인하는 로직
			MemberVO vo= (MemberVO)returnObj; // 다운캐스팅
			if(vo.getRole().equals("ADMIN")) {
				System.out.println("+++++ ADMIN +++++");
			}
			else {
				System.out.println(" 일반사용자 입장 ");
			}
		}
		else if(returnObj instanceof BoardVO) {
			System.out.println("Board정보를 반환받았습니다.");
		}
		else {
			System.out.println("알수없는 반환값입니다.");
		}
	}

 

 

[Object returnObj]

시점이 AfterThrowing일때 사용 가능하다. 핵심관심 수행중 오류가 나타났을때의 오류정보를 사용할 수 있다.

	public void atLog(JoinPoint jp,Exception excepObj) {
		String methodName=jp.getSignature().getName();
		System.out.println("호출된 핵심관심: "+methodName);
		System.out.println("반환된 예외: "+excepObj);
		if(excepObj instanceof IllegalArgumentException) {
			System.out.println("실습을위해서 일부러 예외를 만든상황입니다.");
		}
		else if(excepObj instanceof NumberFormatException) { // 예외 확인후 추가가능
			System.out.println("타입이 올바르지않습니다.");
		}
		else if(excepObj instanceof Exception) {
			System.out.println("미확인 예외발생!!!");
		}
	}

 

[ProceedingJoinPoint pjp]

시점이 around일때 사용 가능하다.

around : 핵심로직의 전체를 주관할 수 있다. 필터와 유사하게 동작함!
핵심관심을 인자로 받아와서 앞뒤작업을 수행함!!
->모든 around관련 어드바이스는 ProceedingJoinPoint (pjp)가 인자로 반드시 존재해야한다.

public Object aroundLog(ProceedingJoinPoint pjp) throws Throwable {
		StopWatch sw=new StopWatch();
		sw.start();
		Object obj=pjp.proceed(); // 수행할 핵심관심
		sw.stop();//수행시간을 알 수 있다.
		String methodName=pjp.getSignature().getName();
		System.out.println("호출된 핵심관심: "+methodName);
		System.out.println("걸린시간: "+sw.getTotalTimeMillis());		
		return obj;
	}

 


 

[어노테이션을 사용한 횡단관심]

1. @을 사용할 것이라고 설정하면서 시작!

 

-applicationContext.xml-

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>


2. @Pointcut 설정
어드바이스에 포인트컷을 설정
"참조 메서드" : 로직이 비어있음. 식별을 목적으로 하기 때문

각각의 로그가 같은 포인트 컷을 참조하고 있기 때문에 클래스를 따로 빼보자!

 

-pointcutCommon

package com.test.app.common;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class PointcutCommon {
	@Pointcut("execution(* com.test.app..*Impl.*(..))")
	public void aPointcut() {} // 참조 메서드
	@Pointcut("execution(* com.test.app..*Impl.get*(..))")
	public void bPointcut() {}
}


3. 어드바이스의 동작시점을 설정하는 @
참조메서드를 이용
4. aspect 결합, 객체화

 

-LogAdvice.java

package com.test.app.common;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;

import com.test.app.board.BoardVO;
import com.test.app.member.MemberVO;

@Service
@Aspect // == 4. 결합 : 포인트컷 + 어드바이스
public class LogAdvice {
	@Before("PointcutCommon.bPointcut()")//3. 어드바이스의 동작시점을 설정하는 @
	public void beforeLog(JoinPoint jp) {
		// jp -> 어떤 핵심관심이 호출되었는지에대한 정보가 담겨있음!
		System.out.println("beforeLog");
		String methodName=jp.getSignature().getName();
		System.out.println("호출된 핵심관심: "+methodName);
		Object[] args=jp.getArgs();
		System.out.println("사용된 인자");
		for(Object v:args) {
			System.out.println(v);
		}
	}
	@AfterReturning(pointcut="PointcutCommon.bPointcut()",returning="returnObj")//3. 어드바이스의 동작시점을 설정하는 @
	public void arLog(JoinPoint jp,Object returnObj) {
		// Object returnObj : 바인드 변수 -> 컨테이너에게 설정을 해주어야한다!!!
		System.out.println("afterReturning 로그");
		String methodName=jp.getSignature().getName();
		System.out.println("호출된 핵심관심: "+methodName);
		System.out.println("반환값: "+returnObj);
		if(returnObj instanceof MemberVO) { // 캐스팅 가능여부를 확인하는 로직
			MemberVO vo= (MemberVO)returnObj; // 다운캐스팅
			if(vo.getRole().equals("ADMIN")) {
				System.out.println("+++++ ADMIN +++++");
			}
			else {
				System.out.println(" 일반사용자 입장 ");
			}
		}
		else if(returnObj instanceof BoardVO) {
			System.out.println("Board정보를 반환받았습니다.");
		}
		else {
			System.out.println("알수없는 반환값입니다.");
		}
	}
	@AfterThrowing(pointcut="PointcutCommon.aPointcut()",throwing="excepObj")
	public void atLog(JoinPoint jp,Exception excepObj) {
		String methodName=jp.getSignature().getName();
		System.out.println("호출된 핵심관심: "+methodName);
		System.out.println("반환된 예외: "+excepObj);
		if(excepObj instanceof IllegalArgumentException) {
			System.out.println("실습을위해서 일부러 예외를 만든상황입니다.");
		}
		else if(excepObj instanceof NumberFormatException) { // 예외 확인후 추가가능
			System.out.println("타입이 올바르지않습니다.");
		}
		else if(excepObj instanceof Exception) {
			System.out.println("미확인 예외발생!!!");
		}
	}
	@Around("PointcutCommon.aPointcut()")//3. 어드바이스의 동작시점을 설정하는 @
	public Object aroundLog(ProceedingJoinPoint pjp) throws Throwable {
		StopWatch sw=new StopWatch();
		sw.start();
		Object obj=pjp.proceed(); // 수행할 핵심관심
		sw.stop();//수행시간을 알 수 있다.
		String methodName=pjp.getSignature().getName();
		System.out.println("호출된 핵심관심: "+methodName);
		System.out.println("걸린시간: "+sw.getTotalTimeMillis());		
		return obj;
	}
}

 

댓글