[Spring 실습] 커스텀 어노테이션으로 AOP 구현

Jiwoo Jung·2024년 11월 7일
0

GDGoC Spring 스터디

목록 보기
8/15

커스텀 어노테이션과 AOP를 활용한 실행 시간 로깅 관점 구현

코드

전체 구조

src/main/java/
└── com/
    └── jiwoo/
        └── gdg_spring_week04/
            ├── GdgSpringWeek04Application.java
            ├── config/
            │   └── AppConfig.java
            ├── aspect/
            │   └── LogExecutionTimeAspect.java
            │   └── LogExecutionTime.java
            ├── controller/
            │   └── Controller.java
            └── service/
                └── SampleClass.java

config 패키지

└──AppConfig.java

package com.jiwoo.gdg_spring_week04.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}

aspect 패키지

└──LogExecutionTimeAspect.java

package com.jiwoo.gdg_spring_week04.aspect;

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 LogExecutionTimeAspect {
    private static final Logger logger = LoggerFactory.getLogger(LogExecutionTimeAspect.class);

//    @Around("@annotation(com.jiwoo.gdg_spring_week04.aspect.LogExecutionTime)")
    @Around("@annotation(LogExecutionTime)")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object proceed = joinPoint.proceed();
        long executionTime = System.currentTimeMillis() - start;

        logger.info("{} executed in {}ms", joinPoint.getSignature(), executionTime);
        return proceed;
    }
}

└──LogExecutionTime.java - 커스텀 인터페이스 클래스

package com.jiwoo.gdg_spring_week04.aspect;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExecutionTime {
}

controller 패키지

└──Controller.java

package com.jiwoo.gdg_spring_week04.controller;

import com.jiwoo.gdg_spring_week04.service.SampleClass;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/sample")
public class Controller {

    @Autowired
    private SampleClass sampleClass;

    @GetMapping("/serve")
    public String serve() throws InterruptedException{
        sampleClass.serve();
        return "Service excuted";
    }
}

service 패키지

└──SampleClass.java

package com.jiwoo.gdg_spring_week04.service;

import com.jiwoo.gdg_spring_week04.aspect.LogExecutionTime;
import org.springframework.stereotype.Component;

@Component
public class SampleClass {

    @LogExecutionTime
    public void serve() throws InterruptedException{
        Thread.sleep(2000);
    }
}

실행

http://localhost:8080/sample/serve

❌ 커스텀 어노테이션과 Aspect가 다른 패키지에 있을 때 로그 안뜸
→ 다른 패키지에 있을 때는 경로 생략 불가. 경로를 다음과 같이 지정해줘야됨.
@Around("@annotation(com.jiwoo.gdg_spring_week04.aspect.LogExecutionTime)")

⇒ 같은 패키지로 이동해서 실행

정상 작동 로그 확인

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v3.3.4)

2024-10-09T15:41:49.007+09:00  INFO 18572 --- [gdg-spring-week04] [           main] c.j.g.GdgSpringWeek04Application         : Starting GdgSpringWeek04Application using Java 21.0.4 with PID 18572 (C:\Users\cse\OneDrive\문서\workspace\spring\gdg-spring-week04\gdg-spring-week04\out\production\classes started by cse in C:\Users\cse\OneDrive\문서\workspace\spring\gdg-spring-week04)
2024-10-09T15:41:49.013+09:00  INFO 18572 --- [gdg-spring-week04] [           main] c.j.g.GdgSpringWeek04Application         : No active profile set, falling back to 1 default profile: "default"
2024-10-09T15:41:51.005+09:00  INFO 18572 --- [gdg-spring-week04] [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port 8080 (http)
2024-10-09T15:41:51.027+09:00  INFO 18572 --- [gdg-spring-week04] [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2024-10-09T15:41:51.027+09:00  INFO 18572 --- [gdg-spring-week04] [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.30]
2024-10-09T15:41:51.117+09:00  INFO 18572 --- [gdg-spring-week04] [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2024-10-09T15:41:51.118+09:00  INFO 18572 --- [gdg-spring-week04] [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2004 ms
2024-10-09T15:41:51.936+09:00  INFO 18572 --- [gdg-spring-week04] [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 8080 (http) with context path '/'
2024-10-09T15:41:51.966+09:00  INFO 18572 --- [gdg-spring-week04] [           main] c.j.g.GdgSpringWeek04Application         : Started GdgSpringWeek04Application in 3.76 seconds (process running for 4.39)
2024-10-09T15:41:52.038+09:00  INFO 18572 --- [gdg-spring-week04] [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2024-10-09T15:41:52.039+09:00  INFO 18572 --- [gdg-spring-week04] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2024-10-09T15:41:52.041+09:00  INFO 18572 --- [gdg-spring-week04] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 2 ms
2024-10-09T15:41:54.101+09:00  INFO 18572 --- [gdg-spring-week04] [nio-8080-exec-1] c.j.g.aspect.LogExecutionTimeAspect      : void com.jiwoo.gdg_spring_week04.service.SampleClass.serve() executed in 2014ms

실행 결과

0개의 댓글