AOP : Aspect Oriented Programming 관점지향프로그래밍
- AOP가 필요한 필요한 상황 - 모든 메서드의 호출시간을 측정하고 싶다면
- 시간 측정 기능은 공통 로직. 공통관심사항.
- 핵심 비지니스 로직은 핵심 관심사항.
- 모든 메서드에 소스코드를 남길 것인가?
- 시간 측정 기능과 핵심 비즈니스 로직이 섞이면 유지보수가 어렵다
- 별도의 공통 로직으로 만들기가 어렵다
- 시간 측정 기능의 요구사항 변경시 모든 메서드를 찾아가면서 변경하기가.... 어렵다..
- AOP를 적용하면
- '원하는 곳'에 공통 관심 사항을 적용할 수 있다.
- 시간 측정 AOP 등록
- AOP class 생성
package net.linkednest.test.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class TimeTraceAop {
@Around("execution(* net.linkednest.test..*(..))")
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
System.out.println("START : " + joinPoint.toString());
try {
return joinPoint.proceed();
} finally {
long finish = System.currentTimeMillis();
long timeMs = finish - start;
System.out.println("END : " + joinPoint.toString() + " " + timeMs + " ms");
}
}
}
- @Component어노테이션을 추가로 선언해서 사용할 수도 있고, SpringConfig에 SpringBean을 직접 등록해서 사용할 수도 있다.
- @Around("execution(* hello.hellospring..*(..))")
- Around 어노테이션은 AOP를 적용할 범위를 지정하는 것
- hello.helloworld 패키지 하위의 내용에 적용하겠다는 의미
- SpringBean으로 직접 등록하는 경우(선호)
- SpringConfig.java에서
@Bean
public TimeTraceAop timeTraceAop() {
return new TimeTraceAop();
}
- Console에서 결과확인
START : execution(String net.linkednest.test.controller.MemberController.list(Model))
START : execution(List net.linkednest.test.service.MemberService.findMembers())
START : execution(List org.springframework.data.jpa.repository.JpaRepository.findAll())
Hibernate: select member0_.id as id1_0_, member0_.name as name2_0_ from member member0_
END : execution(List org.springframework.data.jpa.repository.JpaRepository.findAll()) 173 ms
END : execution(List net.linkednest.test.service.MemberService.findMembers()) 181 ms
END : execution(String net.linkednest.test.controller.MemberController.list(Model)) 189 ms
- 장점
- 핵심 관심사항과 공통 관심사항을 분리
- 핵심 관심사항을 유지 가능하게 됨
- (시간 측정 로직을) 별도의 공통 로직으로 생성
- (시간 측정 기능의) 변경 필요하면 이 AOP Class의 로직만 변경하면 됨.
- 원하는 적용 대상을 선택할 수 있다.
- 패키지 단위가 되겠지
- AOP 동작방식 - Proxy개념의 사용
- Spring Bean을 등록할 때 대상이 되는 진짜 Controller, Service 등이 아닌 가짜 Controller, Service 등을 앞에 세워두고 가짜 스프링빈이 끝나고 AOP에서 joinPoint.proceed()가 실행되면 진짜 Class를 호출해줌.
- AOP의 타겟이 전체 패키지 대상인 경우, proxy Controller -> real Controller -> proxy Service -> real Service -> proxy Repository -> real Repository 호출 순이 된다.
- DI의 적용으로 AOP 적용이 가능.