Spring AOP (Aspect Oriented Programming) - 블로그참고

Back-End/Spring 2019. 6. 6. 11:57
728x90
반응형

AOP는 관점 지향 프로그래밍으로 "기능을 핵심 비즈니스 기능공통 기능으로 '구분'하고, 공통 기능을 개발자의 코드 밖에서

필요한 시점에 적용하는 프로그래밍 방법" 이다.




언제 사용되는가??


  

  성능 검사


  트랜잭션 처리


  로깅


  예외 반환


  검증



예를들어 @Transactional, @Cache 같은 어노테이션들은 AOP를 활용하여 동작하게 된다.



구성요소

설명 

 JoinPoint

모듈의 기능이 삽입되어 동작할 수 있는 실행 가능한 특정 위치 

 PointCut

어떤 클래스의 어느 JoinPoint를 사용할 것인지를 결정 

 Advice

각 JoinPoint에 삽입되어져 동작할 수 있는 코드 

 Interceptor

InterceptorChain 방식의 AOP 툴에서 사용하는 용어로 주로  한개의 호출 메소드를 가지는 Advice

 Weaving

PointCut에 의해서 결정된 JoinPoint에 Advice를 삽입하는 과정 (CrossCutting)

 Introduction

정적인 방식의 AOP 기술 

 Aspect

PointCut+Advice+(Introduction) 



패키지를 나눌때 핵심 비즈니스 기능과 공통 기능으로 구분해야 하지만,

평소에 작성하던 프로젝트에는 보통 MVC  구조로 작성되어 있을 것이고, 해당 코드는 핵심 비즈니스 로직이다.

따로 AOP 패키지로 빠져있는 것이 여기서는 공통 로직이다. (분리되어있다)


기존에 작성한 핵심 비즈니스 로직에는 AOP 때문에 단 한글자도 코드가 변경된 것이 있어서는 안된다.

(왜냐하면 AOP는 공통된 기능을 분리를 시키는 거지, 핵심기능을 삭제하거나 변경하는 것이 아니기 때문!!)



-참고-


(나머지 Controller, Service, Dto, Dao는 생략)


LogAspect.java

package com.example.demo.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
 
@Aspect
@Component
public class LogAspect {
    Logger logger =  LoggerFactory.getLogger(LogAspect.class);
    
    //BookService의 모든 메서드
    @Around("execution(* com.example.demo.service.BookService.*(..))")
    /*@Around("execution(* com.example.demo.controller..*.*(..))")*/
    /*@Around("execution(* com.example.demo..*.*(..))")*/
    public Object logging(ProceedingJoinPoint pjp) throws Throwable {

        logger.info("start - " + pjp.getSignature().getDeclaringTypeName() + " / " + pjp.getSignature().getName());
//메소드 실행전 로그 호출
        Object result = pjp.proceed();

        logger.info("finished - " + pjp.getSignature().getDeclaringTypeName() + " / " + pjp.getSignature().getName());
//메소드 실행후 로그 호출
        return result; //Object를 리턴
    }
}

 

MVC를 위해서 Controller, Service, Dto, Dao 등 구색만 갖췄고, Dao는 DB연결 없이 임의의 Book 객체 3개를 넣어놓았다.


LogAspect.java 를 제외하고는 일반적인 예제, 사용 프로젝트 구성과 유사하다.


LogAspect가 이제 핵심 비즈니스 로직과 분리된 공통 로직인 것을 확인할 수 있고, 예제에서는 메소드를 실행하기 전 / 후로 로그를 찍어서

디버깅하기 좋은 코드를 만들었다.


@Aspect, @Component로 이 클래스가 AOP를 바라보는 관점을 정의하고 bean으로 등록하는 것을 정의했다. 


@Around는 메소드의 실행 전 / 후에 공통로직을 적용하고 싶을 때 사용하고 @Before는 메소드 실행 전에, @After은 메소드 실행 후에 공통로직을

적용하고 싶을 때 사용한다.


즉 어느시점에 적용할 것인지를 정의하는 것이다.


@Around ("execution( * com.example.demo.service.BookService.*(...))") 를 통해서 어떤 메소드들이 이 AOP를 적용받을 것인지를 정의했다.


execution(* com.example.demo.service.BookService.*(..))는 com.exemple.demo.service 패키지의 BookService의 모든 

메소드가 적용받을 것이라고 한 것이다.


다양한 표현식을 이용해서 원하는 부분에만 적용할 수 있을 것이다.




======================================================================================================


공통으로 사용될 메소드를 살펴보면 Object를 리턴하도록 되어있는데 아주 중요하다.


왜냐하면 AOP는 메소드를 가로채서 (Proxy) 앞이나 뒤에 필요한 공통로직을 한다고 했기 때문이다.


즉 proceed( )에서 정상적으로 메소드를 실행한 후 리턴 값을 주는데 가로채서 어떤 action을 한 후에 기존 리턴 값을 되돌려 주지

않으면 가로챈 AOP가 결과값을 변경한 것, 지워버린 것과 다름없다.


위 메소드에서는 단순하게 앞 / 뒤로 추가 로깅을 찍어주고 기존 메소드가 실행될 수 있게 pjp.proceed( ); 를 호출했다.


아래 결과를 보면 좀 더 이해할 수 있다.




  

  localhost:8080/으로 접속했을 때 @Around("execution(* com.example.demo.service.BookService.*(..))")의 로그다.


  BookService의 모든 메서드에서만 aop가 적용되므로 helloService의 메서드에는 적용이 되지 않는다.



2018-11-23 12:09:16.834  INFO 11348 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2018-11-23 12:09:16.834  INFO 11348 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2018-11-23 12:09:16.839  INFO 11348 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 5 ms
2018-11-23 12:09:16.840  INFO 11348 --- [nio-8080-exec-1com.example.demo.aop.LogAspect           : start - com.example.demo.service.BookService / findBookByTitle
Book [title=spring, isbn=1488526510, price=30000]
2018-11-23 12:09:16.844  INFO 11348 --- [nio-8080-exec-1com.example.demo.aop.LogAspect           : finished - com.example.demo.service.BookService / findBookByTitle
cs



  이번에는 @Around("execution(* com.example.demo.controller..*.*(..))")의 로그다.


  controller 하위 패키지까지의 모든 메서드가 aop에 적용된다.

 

  service는 controller패키지 하위에 있는 패키지가 아니므로 찍히지 않는 것을 볼 수 있다.



1
2
3
4
5
6
7
2018-11-23 12:15:47.981  INFO 11348 --- [nio-8080-exec-3] com.example.demo.aop.LogAspect           : start - com.example.demo.controller.MyController / index
2018-11-23 12:15:47.981  INFO 11348 --- [nio-8080-exec-3] com.example.demo.aop.LogAspect           : start - com.example.demo.service.BookService / findBookByTitle
2018-11-23 12:15:47.984  INFO 11348 --- [nio-8080-exec-3] com.example.demo.aop.LogAspect           : start - com.example.demo.repository.BookDao / findBookByTitle
2018-11-23 12:15:47.988  INFO 11348 --- [nio-8080-exec-3] com.example.demo.aop.LogAspect           : finished - com.example.demo.repository.BookDao / findBookByTitle
Book [title=spring, isbn=1488526510, price=30000]
2018-11-23 12:15:47.988  INFO 11348 --- [nio-8080-exec-3] com.example.demo.aop.LogAspect           : finished - com.example.demo.service.BookService / findBookByTitle
2018-11-23 12:15:47.988  INFO 11348 --- [nio-8080-exec-3] com.example.demo.aop.LogAspect           : finished - com.



출처: https://jeong-pro.tistory.com/171 [기본기를 쌓는 정아마추어 코딩블로그]


728x90
반응형
: