728x90
스프링 AOP 와 테스트, 자동 설정 원리
- 스프링 프레임워크의 3가지 핵심 기술
스프링 AOP
- 관심사의 분리
- 대상객체 (target object) : 공통 모듈을 적용할 대상 ex) logging 공통모듈 / HotelDisplayService 대상 객체
- 관점 (aspect) : 어드바이스 + 포인트컷
- 어드바이스 (advice) : 공통 로직이 작성된 모듈
- 포인트컷 (point cut) : 적용할 위치 설정
- 조인포인트 (join point) : 어드바이스가 적용된 위치
- 프록시 객체 (proxy object) : 스프링 AOP는 기능을 조합하기 위해 동적으로 프록시객체를 만든다.
스프링 AOP 와 프록시 객체
- 스프링 AOP 프레임워크는 대상 객체를 감싸는 프록시 객체를 동적을 생성.
- 프록시 객체가 클라이언트의 요청을 가로챈다.
- 어드바이스 타입에 따라 적절히 실행.
- 런타임 시 프록시 객체가 생성
- 어드바이스 로직과 대상 객체의 로직이 함께 실행되는 것을 위빙이라고 한다.
- 관점 클래스와 대상 클래스는 Bean 으로 등록되어야 정상 작동 가능.
- 인터페이스를 구현하고 있으면 JDK Proxy 사용
- 인터페이스를 구현하고 있지 않으면 CGLIB 사용
포인트 컷과 표현식
- 포인트 컷은 어드바이스를 적용할 위치를 선정하는 것.
- 포인트 컷 지정자 ( 리턴타입 / 패키지경로 / 클래스 이름 / 메서드 이름 / 인자 )
execution (* com.springboot.example.testService.getMember (..))
- 작성한 포인트 컷을 적용하는 방법
JoinPoint 와 ProceedingJoinPoint
- JoinPoint : 선정된 위치 ( 대상 객체의 메서드 )
- ProceedingJoinPoint 의 메서드인 proceed() 사용 가능
- Around 어드바이스는 반드시 ProceedingJoinPoint 를 주입받아서 proceed() 메서드를 명시적으로 호출해야 한다.
- → Around 는 대상 객체의 메서드를 감싸고 있는 형태이므로, 프레임워크가 관여할 수 없다.
사용법
- @Aspect 을 추가해주어야 하며, 스프링 빈으로 등록하기 위해 @Component 설정 필요.
- 아래 예제는 HotelRequest 의 인자를 가로채서 사용자가 어떤 요청을 했는지 로그로 남기는 예제.
@Slf4j
@Aspect
@Component
@Order(1)
public class ArgumentLoggingAspect {
// 다음의 pointcut expression 들은 모두 HoteDisplayService 의 getHotelsByName() 메서드를 잡을 수 있다.
// @Before("execution(* getHotelsByName(..))")
// @Before("execution(* com.springtour.example.chapter07.service.*.getHotelsByName(..))")
// @Before("execution(* com.springtour.example.chapter07.service.*.get*(..))")
@Before("execution(* *(com.springtour.example.chapter07.controller.HotelRequest, ..))")
public void printHotelRequestArgument(JoinPoint joinPoint) {
String argumentValue = Arrays.stream(joinPoint.getArgs())
.filter(obj -> HotelRequest.class.equals(obj.getClass()))
.findFirst()
.map(HotelRequest.class::cast)
.map(hotelRequest -> hotelRequest.toString())
.orElseThrow();
log.info("argument info : {}", argumentValue);
}
}
- 아래 예제는 메서드가 종료되는 시점 , 메서드가 예외를 발생한 시점에 로그를 남기는 예제.
@Slf4j
@Aspect
@Component
@Order(1)
public class ReturnValueLoggingAspect {
// 객체를 어드바이스 메서드 인자로 받는 변수 이름을 설정가능 -> retVal
@AfterReturning(pointcut = "execution(* getHotelsByName(..))", returning = "retVals")
public void printReturnObject(JoinPoint joinPoint, List<HotelResponse> retVals) throws Throwable {
retVals.stream()
.forEach(response -> log.info("return value : {}", response));
}
// 객체를 어드바이스 메서드 인자로 받는 변수 이름을 설정가능 -> th
@AfterThrowing(pointcut = "execution(* getHotelsByName(..))", throwing = "th")
public void printThrowable(JoinPoint joinPoint, Throwable th) throws Throwable {
log.error("error processing", th);
}
}
애너테이션을 사용한 AOP - 사용자 정의 애너테이션
- 예제 참고 - 400p
- 주의 할점 !
-
- 조인 포인트에서 발생하는 예외를 어드바이스 내부에서 직접 처리하는 것을 지양.
- @Transactional 을 사용하게 되면 예외 발생 시 롤백하고 사용하던 커넥션 객체를 커넥션 풀에 반납하는데, 어드바이스가 예외를 던지지않고 직접 처리하면 트랜잭션 매니저의 예외 처리 부분이 정상적으로 동작하지 않는다.
// 포인트 컷을 지정하는 마킹 애너테이션이므로, 별도의 속성 값을 지정하지 않는다.
@Target({ElementType.METHOD}) // 메서드에 적용
@Retention(RetentionPolicy.RUNTIME) // 런타임시 적용
public @interface ElapseLoggable {
}
-- ElapseLoggable 설정 부분
@Slf4j
@Component
@Aspect
@Order(2)
public class ElapseLoggingAspect {
@Around("@annotation(ElapseLoggable)") // ElapseLoggable 애너테이션이 적용된 모든 메서드가 포인트 컷 대상
public Object printElapseTime(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
log.info("start time clock");
Object result;
try {
// 대상 클래스의 메서드가 실행
result = proceedingJoinPoint.proceed();
} finally {
stopWatch.stop();
String methodName = proceedingJoinPoint.getSignature().getName();
long elapsedTime = stopWatch.getLastTaskTimeMillis();
log.info("{}, elapsed time: {} ms", methodName, elapsedTime);
}
return result; // 반드시 리턴해야 한다.
}
}
-- 에너테이션을 적용할 메서드
@Slf4j
@Service
public class HotelDisplayService implements DisplayService {
@Override
@ElapseLoggable
public List<HotelResponse> getHotelsByName(HotelRequest hotelRequest) {
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
log.error("error", e);
}
return List.of(
new HotelResponse(1000L,
"Ragged Point Inn",
"18091 CA-1, San Simeon, CA 93452",
"+18885846374"
)
);
}
}
728x90
'Books' 카테고리의 다른 글
도파민네이션 (0) | 2023.11.12 |
---|---|
트렌드 코리아 2024 (0) | 2023.11.04 |
스프링부트로 개발하는 MSA 컴포넌트 [5]장 (0) | 2023.08.24 |
스프링부트로 개발하는 MSA 컴포넌트 [1~4]장 (0) | 2023.08.20 |
비전공자를 위한 이해할 수 있는 IT 지식 을 읽고, (0) | 2023.01.03 |
댓글