1 minute read

(1) 에 이어서..

@Component public class SimpleServiceEvent implements EventService {
  @Override public void created() {
    long begin = System.currentTimeMillis();
    try { Thread.sleep(1000);
    } catch (InterruptedException e) {
      e.printStackTrace(); 
    } 
    System.out.println("created");
    System.out.println(System.currentTimeMillis() - begin); 
    } 
    @Override public void operation() {
    System.out.println(System.currentTimeMillis() - begin); try { Thread.sleep(2000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    } 
    System.out.println("operation");
    System.out.println(System.currentTimeMillis() - begin);
    } 
    @Override public void deleted() {
    System.out.println("deleted"); 
    } 
  }

created() 와 operation() 안에는 수행시간을 측정하는 코드를 담고있다.

이제 이 클래스를 활용하는 Runner 를 다음과 같이 만든다.

@Component public class AppRuner implements ApplicationRunner {
    @Autowired EventService eventService;
    
    @Override public void run(ApplicationArguments args) throws Exception {
        eventService.created();
        eventService.operation();
        eventService.deleted();
        } 
      }

실행결과..

created 
1011
operation
2004
deleted

AOP 이용

1) execution expression

위 코드를 보면 수행 시간을 재는 다음 코드가 여러 곳에서 사용되고 있다.

long begin = System.currentTimeMillis(); ... (수행) ... System.out.println(System.currentTimeMillis() - begin);

이 코드는 Aspect 로 묶어서 관리될 필요가 있어보인다.

이제 다음과 같이 Aspect 클래스를 정의하자.

@Component @Aspect public class PerfAspect {
    // Advice 정의 (Around 사용)
    // Point Cut 표현식
    // (com.example.demo 밑에 있는 모든 클래스 중 EventService 안에 들어있는 모든 메쏘드에 이 행위를 적용하라.) 
    @Around("execution(* com.example..*.EventService.*(..))") public Object logPerf(ProceedingJoinPoint pjp) throws Throwable {
        long begin = System.currentTimeMillis();
        Object retVal = pjp.proceed();
        System.out.println(System.currentTimeMillis() - begin); return retVal; 
      } 
    }

  1. @Aspect 로 Aspect 클래스임을 정의한다.

  2. Advice 를 정의한다. Point cut 시점은 @Around 형태로 정의했다.

  3. AOP 를 적용했으므로, 이제 적용될 클래스에서 Aspect 로 대체된 부분은 삭제한다.

2) annotaion 기반

위와 같이 했더니 하나 문제가 있다.

우리는 created() 와 operation() 에만 Apsect 를 적용하고 싶은데 delete() 에도 적용이 됐기 때문이다.

이를 어노테이션 기반 Advice 정의로 해결해보자.

먼저 다음과 같은 어노테이션을 만든다.

@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS) public @interface PerfLogging {
}

Aspect 클래스 수정

@Component 
@Aspect public class PerfAspect {
      @Around("@annotation(PerfLogging)")
      public Object logPerf(ProceedingJoinPoint pjp) throws Throwable {
          long begin = System.currentTimeMillis();
          Object retVal = pjp.proceed();
          System.out.println(System.currentTimeMillis() - begin); return retVal; 
        } 
      }

적용될 메소드에 어노테이션을 붙여준다..

@Component 
public class SimpleServiceEvent implements EventService {
    @PerfLogging 
    @Override 
    public void created() {
      ... 
    } 
    @PerfLogging 
    @Override 
    public void operation() {
      ... 
    } 
    @Override 
    public void deleted() {
      ... 
    } 
  }

3) 특정 bean 기반

다음과 같이 simpleServiceEvent 내 모든 public 메쏘드에다가 적용하는 방법도 있다.

// Aspect 정의 
@Component 
@Aspect 
public class PerfAspect {
    // 빈이 가지고있는 모든 퍼블릭 메쏘드 
    @Around("bean(simpleServiceEvent)")
    public Object logPerf(ProceedingJoinPoint pjp) throws Throwable {
        long begin = System.currentTimeMillis();
        Object retVal = pjp.proceed();
        System.out.println(System.currentTimeMillis() - begin);
        return retVal;
      } 
    }

출처: https://dailyheumsi.tistory.com/202

Categories:

Updated: