본문 바로가기
Java Spring/MVC

[Spring] AOP 사용하기

by GGShin 2022. 6. 18.

AOP란, 사용 이유

AOP(Aspect Oriented Programming)은 layer에 관계없이 적용되어야 하는 기능을 다루기 위한 방법입니다. Web layer, business layer, data layer 등 특정 layer에만 국한되는 것이 아닌 기능들(영어로는 cross-cutting concerns이라고 합니다.)을 다루게 됩니다. 그런 기능들에는 logging, security, transaction등이 있습니다. 

각 객체에 관심을 두는 OOP는 전체적으로 적용되는 기능을 포괄하는데는 약했고, AOP로 그런 단점을 보완할 수 있는 것입니다.

 

AOP를 사용하면 layer별 method 실행 전, 후에 특정한 행위가 일어날 수 있도록 할 수 있습니다(영어로는 intercept라고 합니다. Method 전, 후에 끼어든다는 의미라고 생각하면 됩니다). 예를 들어서, 특정 메뉴를 열람하기 전에 access 권한이 있는지 확인한다거나 하는 기능을 AOP를 통해 추가하는 것입니다. Access 권한 확인을 하는 AOP를 만들어 놓고 여러 군데에서 사용할 수 있으니 코드 효율성도 높아지겠죠?

중요 용어

1. Join point : Join point는 aspect가 적용될 수 있는 point(지점) 후보들을 의미합니다. Method가 될 수도 있고, throw되는 exception일 수도 있고 수정되는 field도 해당될 수 있습니다. 

 

2. PointCut : 어디에있는 joint point에 AOP를 적용할 것인지는 PointCut을 이용해 설정할 수 있습니다. 어디에 intercept(끼어들지)할 지 알려주는 역할을 합니다. PointCut만 따로 모아두는 file을 만들어서 관리해주면 훨씬 쉽게 사용할 수 있습니다.  

 

=> 이 둘을 구분할 좋은 예시를 봐서 해석해서 올려봅니다. 식당에 가면 메뉴판이 있는데, 메뉴판에 나와있는 메뉴들은 우리가 주문할 수 있는 '후보'들입니다. 주문을 해서 식탁에 오를 수도 있고 아닐 수도 있는 대상인 것이죠. 그리고 우리가 후보들 중에서 메뉴를 골라 주문하게 되고, 주문된 음식은 실제로 나오게 됩니다. 이때, 우리가 고를 수 있었던 메뉴판의 메뉴들은 join points에 해당하고, 실제로 주문해서 나온 음식은 pointcut에 해당합니다. 

Join points는 우리가 AOP를 적용할 수 있는 후보들이고, Point cut은 실제로 AOP를 적용한 대상이 되는 것입니다.☺️

 

3. Advice : Aspect가 intercept해서 무슨일을 할 지 알려주는 것을 advice라고 부릅니다.

 

4. Weaving : Method calls에 AOP를 적용하는 과정을 weaving이라고 부릅니다. 그리고 weaving을 수행하는 프레임워크를 weaver라고 부릅니다.

 

AOP annotations

AOP로 끼어들기(intercept)를 할 때는 method call 직전에나 직후에 끼어들기를 할 수 있습니다. 그래서 annotation들의 이름도 이를 십분 반영한 이름이여서 기억하기가 쉽습니다.

 

1. @Aspect

먼저 AOP로서 역할을 할 method가 담긴 class의 class명 위에 @Aspect를 달아 aspect로서의 역할을 명시해 줍니다. 

그리고 @Configuration 또는 @Comonent도 같이 붙여주어야 합니다. 

 

@Aspect
@Component
public class TimeAop {

	//...
    
}

 

이렇게 붙여주면 됩니다.

 

아래 나오는 Annotation들은 언제 intercept가 일어날지 지정해주는 것들 입니다. 

 

2. @Before

@Before를 붙이면 method가 call되기 직전에 AOP를 intercept해줍니다. 

 

   @Before("execution(* com.ggshin.prac.user.UserService.signup(..))")
    public void beforeTest() {
        System.out.println("BEFORE");
    }

 

pointcut을 살펴보면

"user package의 UserService class file 내부의 어떤 파라미터인지 관계 없이 signup()이라는 method"를 intercept가 적용될 경로로 지정해준 것입니다. 그리고 @Before이므로 해당 경로의 메서드 앞부분에 beforeTest() method가 호출되게 됩니다.

 

3. @After, @AfterReturning, @AfterThrowing

@After를 붙이면 method가 call된 직후에 그 결과가 성공적이든 실패이든 AOP를 intercept 해줍니다. 

@AfterReturning은 method가 call된 직후 그 결과가 문제없이 성공되었을 때 AOP를 intercept 해줍니다.

@AfterThrowing method가 call된 직후 exception이 throw된 경우에 AOP를 intercept 해줍니다.

 

@AfterReturning("com.ggshin.codestatesprac.aop.Pointcuts.onSingupMethod()")
public void afterTest() {
  System.out.println("AFTER Returning");
}

 

@AfterReturning으로 sinup() method가 성공하면 intercept하도록 지정해주었습니다.

콘솔 결과를 확인해보니 정상적으로 동작했음을 알 수 있었습니다. 

 

 

 

 

4. @Around

@Around를 사용하면 Before일때와 After일때 모두 명시할 수가 있습니다. 

 

 //@Around를 사용하면 before 또는 after에 (proceedingJoinpoint.proceed() 전,후) 무슨 일을 할 수 있을 지 명시할 수 있다!!૮ ˶ᵔ ᵕ ᵔ˶ ა
    @Around(value = "com.ggshin.prac.aspect.CommonJoinPointConfig.businessLayerExecution()")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        //start time = x
        long startTime = System.currentTimeMillis();
        //allow execution
        proceedingJoinPoint.proceed();
        //end time = y
        long endTime = System.currentTimeMillis();

        long timeTaken = endTime - startTime;
        logger.info("Time taken by {} is {}", proceedingJoinPoint, timeTaken);
    }

 

위의 예시를 보면 proceedingJoinPoint.proceed() 부분이 joinpoint를 실행하는 부분이고 

그 구문을 기점으로 전과 후에 특정한 AOP를 수행하게 할 수 있습니다. 

위 예시에서는 method 호출 전의 시간을 변수에 저장하고, 호출 직후의 시간을 변수에 따로 저장하여 

그 둘 사이에 얼마만큼의 시간이 걸렸는지 확인하고 있습니다. 

 

+ 그리고 AOP를 사용하려면 dependency를 추가하거나 @Aspect를 붙인 class에 @EnableAspectJAutoProxy를 붙여주어야 aop를 활성화시킬 수 있습니다.

 

Pointcut.java 파일 만들기 

여러 pointcut을 한데 모아 관리하는 파일을 따로 만들어서 사용하는 방법도 있습니다.

 

import org.aspectj.lang.annotation.Pointcut;

public class Pointcuts {

    @Pointcut("execution(* start.aop.order..*(..))")
    public void allOrder(){}

    @Pointcut("execution(* *..*Service.*(..))")
    public void allService(){}

    @Pointcut("allOrder() && allService()")
    public void orderAndService(){}
}

 

이렇게 포인트컷을 모아두면 @Before, @After 등의 포인트컷 명시할 때 pointcut으로 지정된 method의 참조 주소를 사용하면 됩니다.

 

    @Before("com.ggshin.codestatesprac.aop.Pointcuts.allSerivce()")
    public void beforeTest() {
        System.out.println("BEFORE");
    }

 

간략하게 AOP의 개념과 사용방법에 대해 알아보았는데,

앞으로 학습을 하면서 보여드릴 수 있는 예시가 있다면 추가적으로 작성하려고 합니다 :)

감사합니다!


참고 자료

 

https://stackoverflow.com/questions/15447397/spring-aop-whats-the-difference-between-joinpoint-and-pointcut

 

Spring AOP: What's the difference between JoinPoint and PointCut?

I'm learning Aspect Oriented Programming concepts and Spring AOP. I'm failing to understand the difference between a Pointcut and a Joinpoint - both of them seem to be the same for me. A Pointcut is

stackoverflow.com

https://coderanch.com/t/485525/frameworks/Difference-Joint-Point-Point-Cut

 

Difference between Joint Point and Point Cut (Spring forum at Coderanch)

 

coderanch.com

https://www.baeldung.com/spring-aop

 

Introduction to Spring AOP | Baeldung

Discover the core Spring AOP along with its basic terminology.

www.baeldung.com

 

반응형