본문 바로가기
Backend/Spring Framework

Spring Framework 에서 AOP 로 Logging 서비스 만들기

by 지구 2019. 10. 23.

AOP 카테고리의 첫 게시물에서는 너무 예전 버전을 중심으로 작성했었고,
이 게시물의 마지막은 '요즘은 너무 캡슐화, 추상화가 잘 되어있다..' 였는데 ㅋㅋㅋ 이제야 그 방법을 통해! AOP 를 만들어 보았습니다.

이전 게시물 -> https://vvh-avv.tistory.com/7

 

AOP 기본 정리

앞서, AOP와 AOP에서 자주등장하는 단어들을 정리한 페이지가 있으니 참고하자. 2018/05/01 - [용어정리] - 05) AOP 일상생활에 빗대어 AOP를 쉽게 이해하려면 은행시스템의 입출금기능을 구현한다고 생각해보자...

vvh-avv.tistory.com

 

[개발 방향]
우선, (기본 Spring Framework 세팅이 다 되어있다는 가정하에) 정의한 개발방향은 아래와 같았다.

1. Controller 가 아닌 특정 Method 에 로그를 찍을 것
2. Custom Annotation 을 만들어서 사용이 편리하도록 개발할 것
3. Method 별로 보기 쉽도록 Key 를 전달하여 로그를 찍을 수 있게 할 것

 

[개발 진행]
1번을 하기 위해 2번인 Custom Annotation 파일을 만들었다.

/**
 * Logging Annotation
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LoggingAnnotation {

    // Method 별 보고 싶은 Key 전달
    public String logKey() default "";
}
@Target(ElementType.METHOD) (1번의) 메소드 단위로 실행할 수 있도록 세팅
@Retention(RetentionPolicy.RUNTIME)

런타임 시 작동할 수 있도록 세팅
(AOP 사용 시 런타임으로 설정하지 않으면 동작하지 않으니 주의!)

 

그 뒤로 로깅서비스를 담당 할 Aspect 파일을 만들었다.

@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public class LogPrintAspect {

    private final HttpServletRequest request;


    /**
     * 메인 로직을 타기 전에 Request 에서 값을 꺼내와 로그를 찍음
     *
     * @see LoggingAnnotation
     * @param loggingAnnotation - logKey
     */
    @Before("@annotation(loggingAnnotation)")
    public void beforeLogging (LoggingAnnotation loggingAnnotation) {
        // custom log print..
        
        log.info("[logKey] : " + loggingAnnotation.logKey());
        log.info("[ip] : " + request.getRemoteAddr());
    }
}
@Slf4j log.info(~~) 찍을거니까 선언
@Aspect Spring 에서 이 파일을 AOP 파일로 인식 할 수 있도록 선언
@Component 해당 파일을 Bean 으로 등록시키기 위해서 선언
@RequiredArgsConstructor AOP에서 HttpServletRequest 를 사용하기 위해서 선언

 

[파일 분석]

1.
뭔가 joinPoint 의 로직 전/후를 굳이 나눠서 할건 아니고, 그냥 로직 전에 "여기 들어왔어~" 하는 로그만 찍을거라서
@PointCut 이나 @Around 나 @After 는 선언안하고 @Before 만 선언했다.
-> PointCut Extention 으로는 Annotation 을 사용했을 때만 타면 되니까 "@annotation(어노테이션 인터페이스 파일명)" 이렇게 함!

 

2.
그렇다면 Controller 에서 Method 단위로 Annotation 을 쓴다고 했는데, 어떻게 사용하냐!

@GetMapping("/main")
@LoggingAnnotation(logKey = "This is LogKey")
public ModelAndView RealMain() throws Exception{
   // main logic
   
   return new ModelAndView()
}

-> 이렇게 사용하면 된다. Controller 에서 Parameter 로 logKey 를 넘겨주는 값은,
Aspect 파일에서 인자로 LoggingAnnotation 을 불러.logKey() 로 꺼내면 꺼내와 진다 :)

 

3.
그리고 들어왔으니 ClientIP 같은거를 AOP 에서 뽑기 위해 HttpServletRequest 가 필요했고,
검색해보니 이렇게 사용하면 된다- 라고 하는데, Spring 버전 3.x(?) 이상이면 그냥 내가 하드코딩처럼 하지 않아도
@Autowired 로 HttpServletRequest 를 선언할 수 있다. (하지만 생성자주입을 권장하니 @RequiredArgsConstructor 를 사용)
(ps. AOP 에서 Request 를 사용하기, HttpServletRequest 사용하기 를 검색해도 잘 안됐어서 부제로 뽑을까 했다 ㅋㅋ)

HttpServletRequest request = ((ServletRequestAttributes)(RequestContextHolder.currentRequestAttributes())).getRequest();

-> 이렇게 사용하지 않아도 된다는게 <중요!!> 하다. 내가 아닌 스프링에게 주입을 맡기자 :)

 

이번 기회에 이론으로만 알고 있던 AOP 개념을 명확히 하는 계기가 되었다.
그리고 Custom Annotation 은 꼭 만들어 보고 싶었는데! 드디어 도전해봤다.
이렇게 한 발자국 더 성장하는 개발자가 되어 뿌듯합니다 ^-^//

 

[참고 사이트]
1) AOP 전반적인 사용 가이드 : https://www.baeldung.com/spring-aop-annotation
2) AOP 에서 파라미터 전달 방법 : http://blog.naver.com/PostView.nhn?blogId=platinasnow&logNo=220129414824

 

혹시나 이 게시물에 오타나, 잘못된 정보가 있으면 편하게 댓글부탁드립니다! 감사합니다 :D

 

반응형

댓글