개인적인 사정으로 글이 많이 늦었습니다. 이전 글을 올린 지 한달 가까이가 지났네요. ;;

 

이번에는 AOP 글은 실제 AOP 사용 및 결과에 대한 예제입니다. 

 

AOP 표현법만 참고 하시려면, 해당 AOP Pointcut 표현법 링크를 클릭해주세요. 

 

SpringBoot 에서 AOP 를 활용하려면 다음과 같은 조건이 필요합니다. 

 

아래는 build.gradle 파일에 선언된 AOP 관련 lib 입니다. 

(버전정보는 본인의 SpringBoot 버전에 맞추어 사용하면 됩니다. )

implementation 'org.springframework.boot:spring-boot-starter-api:2.4.5'

 

그 다음은 @SpringBootApplication 이 선언된 메소드에 AOP 를 사용한다고 선언해야 합니다. 

내부적으로 많은 원리가 있을거라고 생각하지만.. ㅋ 깊게 공부하지 않았으니 SKIP..

일단 AOP 사용을 위해 @EnableAspectJAutoProxy 를 선언해줍니다. 

( 아래 샘플의 CONF_FILE= "...." 은 그냥 SpringBoot 수행 시 설정파일이라 무시하셔도 무관합니다. )


@EnableAspectJAutoProxy
@SpringBootApplication
public class SpringBootApplication
{
    private static final String CONF_FILE = "spring.config.location=classpath:application.yml"

    public static void main( String[] args )
    {
        new SpringApplicationBuilder( SpringBootApplication.class )
                .properties( CONF_FILE )
                .run ( args );
    }
}

서두가 길었습니다. 이제 실제 AOP 사용 예제와 그 결과를 확인해보겠습니다. 

 

샘플은 Before , Around, After 순으로 해보겠습니다. 

( Before, Around .... 부분이 궁금하시면 앞서 설명한 AOP 는 무엇인가? 페이지를 참고 해주세요.  

 

AOP 호출 테스트를 위한 Control 함수 입니다. 

 @RestController
 public class AopTestPartCTRL
 {
     // slf4j Logger 사용
     private static final Logger loclog = LoggerFactory.getLogger( AopTestPartCTRL.class );

     @RequestMapping( value = "aopTestPart1" )
     public ResponseEntity aopTestCtrl_1( HttpServletRequest request, @RequestParam(required=false) String testParam )
     {
         // 단순히 controller 메소드명을 로깅
         loclog.info( "CTRL Method ---> {}", Thread.currentThread().getStackTrace()[1].getMethodName() );

         // URL ( ~~/aopTestPart1 ) 호출 시 200 성공 및 'AOP-TEST_PART_1' 이 리턴
         return new ResponseEntity( "AOP-TEST_PART_1", HttpStatus.OK );
     }
 }

 

[ @Before Aop ]

 @Component
 @Aspect
 public class TestAspectOrder_1
 {
     // slf4j Logger 사용
     private static final Logger loclog = LoggerFactory.getLogger( TestAspectOrder_1.class );

     @Before( "execution(* com.foxy.wany..*Test.Wany*(..) )"
     public void beforeAopTest_1( JoinPoint jp )
     {
          Object args[] = jp.getArgs();
          
         // beforeAopTest_1 호출 대상 메소드
         loclog.info( "Before ---> Target Method : {}", jp.getSignature().getName() );          

         // beforeAopTest_1 호출 대상 메소드 인자 갯수
         loclog.info( "Before ---> Target Method Param len : {}", args.length );          
     }
 }

 

[ RESULT ]

 Before ---> Target Method : aopTestCtrl_1
 Before ---> Target Method param len : 2
 CTRL Method ---> aopTestCtrl_1

위 결과에서 보듯이 Before AOP 가 먼저 호출 후에 controller 메소드 aopTestPart1 가 호출 되었습니다.

 

 

[ @After , @AfterReturning Aop ]

 @Component
 @Aspect
 public class TestAspectOrder_1
 {
     // slf4j Logger 사용
     private static final Logger loclog = LoggerFactory.getLogger( TestAspectOrder_1.class );


     @After( "execution(* com.foxy.wany..*Test.Wany*(..) )" 
     public void afterAopTest_1( JoinPoint jp )
     {
          Object args[] = jp.getArgs();
          
         // afterAopTest_1 호출 대상 메소드
         loclog.info( "After---> Target Method : {}", jp.getSignature().getName() );          

         // afterAopTest_1 호출 대상 메소드 인자 갯수
         loclog.info( "After ---> Target Method Param len : {}", args.length );          
     }


     @AfterReturning( value="execution(* com.foxy.wany..*Test.Wany*(..) )" , returning="returnData" 
     public void afterAopTest_1( JoinPoint jp , ResponseEntity  returnData )
     {
          Object args[] = jp.getArgs();
          
         // afterAopTest_1 호출 대상 메소드
         loclog.info( "AfterReturn---> Target Method : {}", jp.getSignature().getName() );          

         // afterAopTest_1 호출 대상 메소드 인자 갯수
         loclog.info( "AfterReturn ---> Target Method Param len : {}", args.length );       

         // afterAopTest_1 호출 대상 메소드의 리턴 데이터
         loclog.info( "AfterReturn returning ---> {}", returnData );         
     }

 }

 

[ RESULT ]

 CTRL Method ---> aopTestCtrl_1
 AfterReturn ---> Target Method : aopTestCtrl_1
 AfterReturn ---> Target Method param len : 2
 AfterReturn returning ---> <200 OK OK, AOP-TEST_PART_1, []>
 After ---> Target Method : aopTestCtrl_1
 After ---> Target Method param len : 2

위와 같은 결과가 나옵니다. 

@After 특성상 대상 메소드 호출 완료 후 AOP 가 호출되는 것을 확인할 수 있으며, @After 과 @AfterReturning 의 차이

점은 @AfterReturning 은 대상 메소드의 리턴값을 받을 수 있는 것입니다. 

 

단 주의할 이 2가지 정도 있습니다.

1. @AfterReturning 내 returning 에 선언된 'returnData' 명칭이 afterAopTest_1 메소드 내 parameter 명이

   'returnData'과 동일 해야 합니다. 

2. 대상 메소드 리턴 타입과 afterAopTest_1 메소드 내 parameter 타입이 동일해야 합니다. 

 

만약 위 1,2 가 수락되지 않을 경우, compile 오류 또는 @AfterReturning 이 호출 되지 않습니다. 

 

 

[ @Around ]

 @Component
 @Aspect
 public class TestAspectOrder_1
 {
     // slf4j Logger 사용
     private static final Logger loclog = LoggerFactory.getLogger( TestAspectOrder_1.class );


     @Around( "execution(* com.foxy.wany..*Test.Wany*(..) )" 
     public Object aroundAopTest_1( ProceedingJoinPoint pjp )
     {
          Object args[] = jp.getArgs();
          
         // afterAopTest_1 호출 전 
         loclog.info( "Around before ---> Target Method : {}", pjp.getSignature().getName() );          

         // afterAopTest_1 호출 전
         loclog.info( "Around before ---> Target Method Param len : {}", args.length );          

         // afterAopTest_1 수행
         Object rtnObj = pjp.proceed();

         // afterAopTest_1 호출 후 리턴값
         loclog.info( "Around after ---> rtnObj  : {}", rtnObj );          

         return rtnObj;
     }
 }

 

[ RESULT ]

 Around before ---> Target Method : aopTestCtrl_1
 Around before ---> Target Method param len : 2

 CTRL Method ---> aopTestCtrl_1

 Around after ---> <200 OK OK, AOP-TEST_PART_1, []>

위와 같은 결과가 나옵니다.

@Around 의 경우는 pjp.proceed();  호출 전/후 로 나눌 수 있습니다. 

pjp.proceed(); 호출 전에 @Around 내 기능을 수행하고, proceed(); 호출 시점에서 대상 메소드 로직이 수행됩니다. 

pjp.proceed(); 호출 후 다시 @Around 내 기능이 수행되는 것입니다. 

 

즉, @Around 에서 proceed() 를 호출 하지 않을 경우는 대상 메소드를 호출하지 않습니다. 

때문에 반드시 proceed() 를 선언해 주어야 합니다. 

 

또한 @Around 선언된 메소드는 리턴 타입을 가져야 할 수도 있습니다. 

즉, @Around 대상 메소드가 리턴 타입이 존재한다면, @Around 내 에서도 반드시 리턴 타입을 가져야 합니다. 

 Object rtnObj = pjp.proceed();
 . . . . 중략 . . . .
 return rtnObj;

위 처럼 return rtnObj; 을 선언해 주어야, @Around 대상 메소드의 리턴값이 정상적으로 반환됩니다. 

만약 return 해주지 않는다면, 대상 메소드의 리턴값은 처리될 수 없습니다. 

 

 

 

'Framework > SpringBoot' 카테고리의 다른 글

[ 2 ] AOP Pointcut 표현방법  (0) 2021.04.30
[ 1 ] AOP 는 무엇인가?  (0) 2021.04.22

+ Recent posts