SpringFramework - AOP

BbongGu·2023년 4월 18일

SpringFramework

목록 보기
2/3

AOP - Aspect Oriented Programming (관점지향 프로그래밍)

개요

  • 기존 OOP(객체지향 프로그래밍)에서는 수행시간 측정과 같은 공통 관심사항을 여러곳에 적용하려면 중복된 코드가 생겨나는 한계가 있다. -> 이를 해결하기 위해 AOP 등장
  • AOP는 문제를 해결하기 위해 핵신 관심 사항과 공통 관심 사항을 기준으로 프로그래밍 함으로써 공통 모듈을 손쉽게 적용할 수 있게 한다.

OOP와 AOP의 비교

  • OOP는 핵심 관심사항과 부가 관심사항이 붙어있음
  • 핵심 관심사항과 부가 관심사항이 따로 있어 어디에 기능을 붙일지 정함

AOP의 적용 예시

  • 간단한 메소드의 성능 검사
  • 트랜젝션 처리
  • 예외 반환
  • 아키텍처 검증 ...

Spring AOP 용어

  1. Advice : 어느 시점에 어떤 공통 관심기능(Aspect)을 적용할지 정의한 것

  2. JoinPoint : Aspect가 적용 될 수 있는 지점.(Spring에서는 method), 즉 target객체가 구현한 인터페이스의 모든 method는 JoinPoint가 된다.

  3. Pointcut : 공통 관심사항이 적용될 JoinPoint, Advice를 적용할 target의 method를 선별하는 정규 표현식이 사용된다.

    @Around(value = "execution(* board.model.dao.Board*.list*(..))")
    // 모든 반환, board/model/dao에 있는 Board로 시작하는 클래스 의 list로 시작하는 method가 Pointcut이 된다.
  4. Aspect(Class) : 여러 객체에서 공통으로 적용되는 공통 관심 사항, AOP의 기본 모듈이다.

  5. Weaving : 어떤 Advice를 어떤 Pointcut에 적용시킬 것인지에 대한 설정

Spring AOP 특징

  • Spring은 프록시 기반 AOP를 지원
  • Spring AOP는 method JoinPoint만 지원

AOP 구현 - Advice종류

  1. Before Advice : 대상객체의 method 실행이 시작되기 전 Aop가 실행
  2. After Returning Advice
    • 대상 객체의 method 실행이 정상적으로 끝난 뒤 실행
    • return type : void
    • args : org.aspectj.lang.JoinPoint 객체를 받거나 없어도 된다, 대상 method에서 반환되는 특정 개체 타입의 값을 argument로 받을 수 있다.
  3. Around Advice
    • 위의 네 가지 Advice를 다 구현 할 수 있는 Advice
    • return type : Object
    • argument : org.aspectj.lang.ProceedingJoinPoint를 반드시 첫 argument로 지정
  4. After Advice
    • 대상 객체의 method가 정상적으로 실행 되었는지 아니면 exception을 발생 시켰는 지의 여부와 상관없이 실행 종료 후 공통 기능 적용
    • return type : void
    • argument : 없거나 JoinPoint
  5. After Throwing Advice
    • 대상 객체의 method 실행 중 예외가 발생한 경우 실행
    • return type : void
    • argument : 없거나 JoinPoint , 대상 method에서 전달되는 예외 객체를 argument로 받을 수 있다.

구현 소스

  1. XML방식
	<bean id="advice" class="com.ssafy.board.aop.LogAdvice"/>
	<aop:config>
		<aop:pointcut id="beforePointcut" expression="execution(* board.model.dao.Board*.write*(..))" />
		<aop:pointcut id="afterPointcut" expression="execution(* board.model.dao.Board*.write*(..))" />
		<aop:pointcut id="aroundPointcut" expression="execution(* board.model.dao.Board*.list*(..))"/>
		<aop:pointcut id="returningPointcut" expression="execution(* board.model.dao.Board*.write*(..))" />
		<aop:pointcut id="throwingPointcut" expression="execution(* board.model.dao.Board*.write*(..))" />
		<aop:aspect ref="advice">
			<aop:before method="logBefore" pointcut-ref="beforePointcut"/>
			<aop:after method="logAfter" pointcut-ref="afterPointcut"/>
			<aop:around method="logAround" pointcut-ref="aroundPointcut"/>
			<aop:after-returning method="logAfterReturning" pointcut-ref="returningPointcut" returning = "returnObj"/> 
			<aop:after-throwing method="logThrowing" pointcut-ref="throwingPointcut" throwing = "e"/>
		</aop:aspect>
	</aop:config>
  1. Annotation 방식
@Component
@Aspect
public class LogAdvice {
	@Before(value = "execution(* board.model.dao.Board*.write*(..))")
	public void logBefore() {
		System.out.println("AOP Before Log");
	}
	@After(value = "execution(* board.model.dao.Board*.write*(..))")
	public void logAfter() {
		System.out.println("AOP After Log");
	}
	@Around(value = "execution(* board.model.dao.Board*.list*(..))")
	public Object logAround(ProceedingJoinPoint jp) throws Throwable {
		System.out.println("AOP Around Before log");
		
		// JointCut
		Object proceed = jp.proceed();
		Object[] args = jp.getArgs();
		for (Object object : args) {
			if(object instanceof Map) {
				Map<String, String> map = (Map) object;
				Set<String> keySet = map.keySet();
				for (Object key : keySet) {
					System.out.println(map.get(key));
				}
			}
		}
		
		System.out.println("AOP Around After log");
		
		return proceed;
	}
	@AfterReturning(value = "execution(* board.model.dao.Board*.write*(..))", returning = "returnObj")
	public void logAfterReturning(JoinPoint joingPoint, Object returnObj) throws Throwable{
		System.out.println("AOP After Returning log");
	}

	@AfterThrowing(value = "execution(* board.model.dao.Board*.write*(..))", throwing = "e")
	public void logThrowing(Exception e) {
		System.out.println("AOP log"+ e.getMessage());
	}
	
	@Around(value = "execution(* board.model.service.Board*.deleteArticleList(..))")
	public Object trace(ProceedingJoinPoint joinPoint) throws Throwable {
		String signature = joinPoint.getSignature().toShortString();
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		Object result = joinPoint.proceed();
		stopWatch.stop();
		System.out.println("아티클 삭제 실행 시간 - " + stopWatch.getTotalTimeMillis()+"ms");

		return result;
	}	
}
profile
개발새내기

0개의 댓글