AOP(2)
(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;
}
}
-
@Aspect 로 Aspect 클래스임을 정의한다.
-
Advice 를 정의한다. Point cut 시점은 @Around 형태로 정의했다.
-
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