Adventure Time - Finn 3
본문 바로가기
Spring

@어노테이션을 이용한 AOP

by hyun9_9 2024. 3. 12.

모든 xml 설정은 @ 으로 바꿀 수 있다
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
를 하게 되면 aop를 @으로 변경

 

먼저  Pointcut 을 클래스로 만든다

package com.spring.biz.common;

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


@Aspect
public class PointcutCommon {
	@Pointcut("execution(* com.spring.biz..*Impl.*(..))")//추상 아님 비어있는 깡통
	public void aPointcut() {}
	
	@Pointcut("execution(* com.spring.biz..*Impl.select*(..))")
	public void bPointcut() {}
}

 

 

                                                                                        ▼

package com.spring.biz.common;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Service;

//bean 역할
@Service //Impl랑 aspect되서 Service 로 같은 곳에서 연결하기 위해 Component가 아닌 Service로 적는게 유리
@Aspect //얘네를 다 묶어줄래? 결합해줄래? 
public class LogAdvice {
	
	
	
	//어떤 pointcut이랑 결합하는지 알려준다.
	@Before("PointcutCommon.aPointcut()") //aPointcut은 추상메서드가 아니다. 
	public void printLog(JoinPoint jp) {
		
		String methodName = jp.getSignature().getName();
		System.out.println("      BEFORE 어드바이스 : " + methodName);
		
		Object[] args = jp.getArgs();
		System.out.println( "     비즈니스 메서드에서 사용하는 인자 : " + args[0]);
		//보통은 인자가 DTO 1개일 확률이 높아서 argsp[0]을 사용한다. 
		for(Object arg:args) {
			System.out.println(arg);
		}
		
		
		System.out.println( "     비즈니스 메서드 수행 전에 로그를 출력");
		
	}
}

 

어노테이션을 사용하여 작성하였다

 

하지만 AfterThrowingAdvice를 사용할땐 조금 다른 걸 확인 할 수 있다

package com.spring.biz.common;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Service;

import com.spring.biz.member.MemberDTO;

@Service
@Aspect
public class AfterThrowingAdvice {
	
//	@Pointcut("execution(* com.spring.biz..*Impl.*(..))")
//	public void aPointcut() {
//		//비어있는 깡통
//	}
	
	@AfterThrowing(pointcut="PointcutCommon.aPointcut()", throwing="exceptObj")
	public void printException(JoinPoint jp, Object exceptObj) {
		String methodName = jp.getSignature().getName();
		System.out.println("      AfterThrowing 어드바이스 : " + methodName);
		
		Object[] args = jp.getArgs();
		System.out.println( "     비즈니스 메서드에서 사용하는 인자 : " + args[0]);
		for(Object arg:args) {
			System.out.println(arg);
		}
		System.out.println("      비즈니스 메서드의 OUTPUT :" + exceptObj );
		
		if(exceptObj instanceof NumberFormatException) {
			System.out.println("값이 숫자가 아닙니다.");
		}
		else if(exceptObj instanceof ArithmeticException) {
			System.out.println("수학적인 오류입니다.");
			System.out.println("일부러 발생시킨 에러입니다.");
		}
		else {
			System.out.println("미확인 에러입니다.");
		}
		
		System.out.println( "     비즈니스 메서드 수행 전에 로그를 출력");

		System.out.println( "     로그 03 예외 발생");
	}
	}

속성 부분이 다른 걸 확인할 수있는데 

@Before는 하나의 속성만 받기때문에 생략되어 pointcut이 사용이 안되는 것을 볼수있고

 

@AfterThrowing 은 100%로 값이 넘어올 수 있기에 속성 필드에 추가하여 사용할 수 있게 되어있습니다

그래서 throwing 을 사용해서 어떤 애러가 나왔는지도 받아볼수있다

 

package com.spring.biz.common;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Service;

import com.spring.biz.member.MemberDTO;

@Service 
@Aspect
public class AfterReturningAdvice {
	
//	@Pointcut("execution(* com.spring.biz..*Impl.select*(..))")
//	public void bPointcut() {
//	//반환이 있어야 하니까 select 랑만 연결	
//	}
	
	@AfterReturning(pointcut="PointcutCommon.bPointcut()", returning="returnObj")
	//핵심관심=> bPointcut이 수행하고 반환한 애를 담을거야 Object returnObj
	public void afterReturningPringLog(JoinPoint jp, Object returnObj) {
		String methodName = jp.getSignature().getName();
		System.out.println("      AfterReturning 어드바이스 : " + methodName);
		
		Object[] args = jp.getArgs();
		System.out.println( "     비즈니스 메서드에서 사용하는 인자 : " + args[0]);
		for(Object arg:args) {
			System.out.println(arg);
		}
		System.out.println("      비즈니스 메서드의 OUTPUT :" + returnObj );
		
		if(returnObj instanceof MemberDTO) { //데이터 확인함
			MemberDTO mDTO = (MemberDTO)returnObj;
			if(mDTO != null) {
				if(mDTO.getRole().equals("ADMIN")) {
					System.out.println("[관리자 로그인]");
					System.out.println(mDTO.getName()+"님 입장");
				}
				else {
					System.out.println("[사용자 로그인]");
				}
			}
		}
		
		System.out.println( "     비즈니스 메서드 수행 전에 로그를 출력");
	}
	
	//바인드 변수
	
	
	
	
}

 

package com.spring.biz.common;

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


@Service
@Aspect
public class AroundAdvice {
	
	@Around("PointcutCommon.aPointcut()")
	public Object aroundPrintLog(ProceedingJoinPoint pjp) throws Throwable { //지금 실행하고 있는 포인트컷. 지금 연결된애 
		
		String methodName = pjp.getSignature().getName(); // 메서드 이름은 시그니처로 가져올수있다.
		
		System.out.println("[BEFORE]");
		
		
		StopWatch sw = new StopWatch(); //시간 가져오는거
		sw.start();
		
		//왜 오브젝트냐면 뭐가 나올지 몰라서!!!
		Object obj = pjp.proceed(); //pjp가 실행이 되면 아웃풋으로 뭔가 뱉어냄
		//throws => 예외가 발생할 수 있어서 
		//11번 라인을 통해서 비즈니스 메서드가 수행된다.
		
		sw.stop();
		
		System.out.println("[AFTER]");
		System.out.println("비즈니스 메서드 : " + methodName);
		System.out.println(" 수행하는데에 걸린 시간 : " + sw.getTotalTimeMillis()+ "(ms)초");
		
		return obj; //내가 수행하고 있는 메서드가 반환이 있을수도 있잖아?
	}
}

'Spring' 카테고리의 다른 글

DAO var.2 사용  (1) 2024.03.15
DAO var.1 -> DAO var.2 설정  (0) 2024.03.14
Advice 동작시점  (0) 2024.03.11
AOP 정리  (0) 2024.03.10
Spring 어노테이션을 이용한 연습  (0) 2024.03.09