Spring

[Spring] Joinpoint, 바인드 변수

코딩 수달 2022. 9. 16. 14:23
반응형

JointPoint  사용 이유 

  • 횡단 관심에 해당되는 어드바이스 메소드를 의미있게 구현하기 위해서는 비즈니스 메서드 정보가 필요함
  • joinpoint를 인자로가지게되면(pjp처럼) 현재 수행중인 비즈니스메서드의 시그니처 등을 알수있음 

- String getName() : 클라이언트가 호출한 메서드 이름 리턴 

- SignaturegetSignature() : 클라이언트가 호출한 메소드의 시그니처 (리턴타입, 이름, 매개변수) 정보가 저장된 Signature 객체를 리턴

- Object [] getArgs() : 클라이언트가 메소드를 호출할 때 넘겨준 인자 목록을 Object 배열로 리턴 


After Returning Advice 

 

- JointPoint jp (매개변수 ) : 클라이언트가 호출한 비즈니스 메서드 정보를 알아내기 위해 선언 

- Object retrunObj (매개변수) : Object 타입의 변수로 바인드 변수라고 함

- 바인드 변수 : 비즈니스  메서드가 리턴한 결과값을 바인딩할 목적으로 사용 (어떤 값이 리턴될지 몰라 Object 타입 선언) 

package com.kim.biz.common;

import org.aspectj.lang.JoinPoint;

import com.kim.biz.member.MemberVO;
							
public class AfterReturningAdvice {						//Object returnObj 바인드 변수 
	public void printLogAfterReturning(JoinPoint jp, Object returnObj) {//핵심메서드 반환값을 가질 returnObj
		String methodName=jp.getSignature().getName();
		//현재 수행중인 포인트컷(핵심로직,CRUD)의 메서드명 
		Object[] args=jp.getArgs();
		//현재 수행중인 포인트컷(핵심로직,CRUD)이 사용하는 인자들의 정보 
		
		System.out.println("수행중인 핵심메서드명: " + methodName);
		System.out.println("사용하는 인자 ");
		System.out.println("==========");
		for(Object v:args) {
			System.out.println(v);
		}
		System.out.println("==========");
		
	      if(returnObj instanceof MemberVO) {
	          MemberVO mvo=(MemberVO)returnObj;
	          if(mvo.getRole().equals("ADMIN")) {
	             System.out.println("관리자입니다.");
	          }
	          else {
	             System.out.println("일반계정입니다.");
	          }
	       }
	       System.out.println("핵심메서드의 반환값: "+returnObj);
	    }
	 }

설정 파일 

- 바인드 변수가 추가되었으므로 스프링 설정 파일에서도 바인드 변수에 대한 매핑 설정을 추가 

(returning 속성 사용)

실행 결과 


After Throwing Advice 

 

- 예외가 발생한 메서드 이름과 발생한 예외 객체의 메세지를 출력하도록 수정 

- 예외 객체를 exceptObj라는 바인드 변수를 통해 받음 (예외 클래스의 최상위 타입인 Exception으로 선언) 

package com.kim.biz.common;

import org.aspectj.lang.JoinPoint;

public class AfterThrowingAdvice {
	public void printLogAfterThrowing(JoinPoint jp, Exception exceptObj) {
		String methodName=jp.getSignature().getName();
		//현재 수행중인 포인트컷(핵심로직,CRUD)의 메서드명 
		Object[] args=jp.getArgs();
		//현재 수행중인 포인트컷(핵심로직,CRUD)이 사용하는 인자들의 정보 
		
		System.out.println("수행중인 핵심메서드명: " + methodName);
		System.out.println("사용하는 인자 ");
		System.out.println("==========");
		for(Object v:args) {
			System.out.println(v);
		}
		System.out.println("==========");
		
		System.out.println("발생한 예외" + exceptObj.getMessage());
		if(exceptObj instanceof IllegalArgumentException) {
			System.out.println("올바르지않은 인자값을 사용했습니다...");
		}else if(exceptObj instanceof NumberFormatException){
			System.out.println("숫자 형식이 아닌 값을 사용했습니다...");
		}else if(exceptObj instanceof Exception) {
			System.out.println("예외가 발생했습니다...");
		}else {
			System.out.println("확인되지않은 에러가 발생했습니다!!! ");
		}
	}
}

설정 파일 

- 비즈니스 메서드에서 발생한 예외 객체를 exceptObj라는 바인드 변수에 바인드하라는 설정 

예외 발생 

아이디가 timo면 예외가 발생되도록 설정 

실행 결과 


Around

 

- 비지니스 메소드 실행 전과 실행 후 Advice 메소드 동작하는 형태

하기 예제에서는 ProceedingJointPoint라는 클래스가 추가되었는데 해당 클래스의 proceed() 의 메서드를 실행함으로서

타겟 오브젝트의 메서드가 실행하게 됨! 해당 코드 전후로 부가기능을 위한 코드를 작성하면 됨 

 

※ 주의할 점은 @Around 어드바이에서만 ProceedingJointPoint를 매개변수로 사용 

 @Before, @After, @AfterReturning, @AfterThrowing 어드바이스에서는 JointPoint를 매개변수로 사용 

Around 어드바이스에서만 proceed() 메서드가 필요하기 때문

package com.kim.biz.common;

import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.util.StopWatch;

//around로 사용할 advice는 반드시 pjp를 input으로 가져야한다! 
// ex) 필터 서블릿 클래스
// ProceedingJoinPoint 은 JoinPoint 상속받은 아이 
// 상속받은 것이기 때문에 JoinPoint 하는 행동을 다 할 수 있다. 

public class AroundAdvice {
	public Object printLogAround(ProceedingJoinPoint pjp) throws Throwable {
		String methodName=pjp.getSignature().getName();
		System.out.println("수행중인 핵심메서드명: " + methodName);
		
		StopWatch sw=new StopWatch();
		sw.start();
		Object returnObj=pjp.proceed(); //수행해야할 포인트컷 
		//pjp.proceed()에 의해 비즈니스메서드가 수행됨!
		sw.stop();
		System.out.println("수행시간: " + sw.getTotalTimeMillis()+"ms");
		return returnObj;	
	}
}

설정파일 

실행결과 

반응형