Web/spring-boot
[Spring] AOP 와 커스텀 어노테이션을 활용한 Logging
부에나온다
2022. 9. 5. 16:34
1. Spring AOP (Aspect Oriented Programming)
- AOP는 관점지향 프로그래밍이라고 불린다.
- 어떤 로직을 기준으로 핵심적인 관점, 부가적인 관점을 나눠보고, 그 관점을 기준으로 각각 모듈화 하는 것이다.
- 예를 들면 비즈니스 로직에서 핵심 로직이 아닐 수 있는 로깅, 보안 등과 같은 내용을 AOP를 통해 분리시키는 것
2. Spring AOP의 주요 용어
- Aspect : AOP를 통해 분리시켜 모듈화 한것
- Target : Aspect를 적용 할 수 있는곳( Class, Method 등)
- Advice : 실질적으로 어떤 일을 해야할 지에 대한 것, 실질적인 부가기능을 담은 구현체
- JoinPoint : Advice가 적용 될 위치, 끼어들 수 있는 지점. 메서드 진입 지점. 생성자 호출 지점. 필드에서 값을 꺼내 올때 등 다양한 시점에서 적용 가능
- PointCut : JointPoin의 상세한ㄴ 스펙을 정의한 것, 'A란 메서드의 진입시점에 호출할 것' 과 같은 더욱 구체적인 Advice 실행될 지점을 정할 수 있음
3. AOP와 커스텀 어노테이션을 활용한 Logging
- 로깅하지 않을 곳은 커스텀 어노테이션을 생성하여 어노테이션을 붙인곳은 로깅이 되지 않도록 한다.
- @NoLogging 커스텀 어노테이션 생성
@Target({ ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface NoLogging {
}
@Aspect
@Component
@Slf4j
public class LogAspect {
@Resource
Tracer tracer;
@Around("within(kr.co.lunasoft.smartstorecoreapi.controller.*) " + "&& !@annotation(kr.co.lunasoft.smartstorecoreapi.common.NoLogging)")
public Object logging(ProceedingJoinPoint pjp) throws Throwable {
String params = getRequestParams();
long startAt = System.currentTimeMillis();
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
.getRequest();
log.info("[{}] " + LogbackKafkaFilter.KAFKA_LOG_FILTER + " REQUEST {} [{}] [{}]", method.getName(), params, request.getRequestURI(), request.getRemoteHost());
Object result = pjp.proceed();
HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getResponse();
long endAt = System.currentTimeMillis();
log.info("[{}] " + LogbackKafkaFilter.KAFKA_LOG_FILTER + " RESPONSE [status : {}] ({}ms)", method.getName(), response.getStatus(), endAt-startAt);
response.setHeader("zipkinId", tracer.currentSpan().context().traceIdString());
return result;
}
}
- 전체 코드를 남길수 없지만 예를 들어서 설명을 하면,
- 먼저 AOP를 적용하기 위해서는 해당 클래스를 @Component 선언하여 Bean을 등록해주고,
- @Aspect 선언하여 이 클래스가 Aspect를 나타내는 (AOP를 적용하겠다는) 클래스라는 것을 명시해줍니다.
- 다음은 타깃 메서드의 Aspect 실행 시점을 지정할 수 있는 어노테이션을 클래스에 선언해줍니다.
- @Around(메소드 실행 전후) : 어드바이스가 타깃메서드를 감싸서 타깃 메서드 호출 전과 후에 어드바이스 기능을 수행
- @Before(메소드 실행 전) : 타깃메서드 실행 전 어드바이스 기능을 수행
- @After(메소드 실행 후) : 타깃메서드 실행 후 어드바이스 기능을 수행
- @AfterReturning(정상적 반환 이후) : 타깃메서드가 성공적으로 결과값을 반환 후에 어드바이스 기능을 수행
- @AfterThrowing(예외 발생 시) : 타깃메서드가 수행 중 예외를 던지게 되면 어드바이스 기능을 수행
- !@annotation 을 선언하여 @NoLogging이 아닐때 어드바이스가 실행되도록 선언해줬습니다.
- within(컨트롤러) 해당 컨트롤러로 호출시 어드바이스 실행 완료되고 어드바이스를 실행하게 해줘서 로그를 남기도록 해줬습니다.
- 저희는 MSA 를 적용하고 있어서 traceId를 추가하여 로깅을 좀더 효율적으로 할 수 있도록 해줬습니다.