코딩 이래요래
AOP를 통한 서비스 계층 로그 분리 본문
AOP를 적용해 로깅 코드 분리 리팩토링
이전에 정리한 블로그 내용 중 AOP 개념을 정리한 적이 있는데, 그 당시에는 간단하게만 정리하고 넘어갔지만, 프로젝트 리팩토링을 통해 개념을 다시 정리 해보려고 한다
Spring Framework 핵심 개념
1. IoC (Inversion of Control) - 제어의 역전 즉, 객체의 생성, 초기화 등 개발자가 직접 제어하는 것이 아닌, 컨테이너가 대신 관리하는 개념 1-1. IoC 구조 ☑️ 기존의 의존성 주입// controllerpublic class User
kh-coding.tistory.com
AOP(Aspect Oriented Programming)란 ?
- OOP 프로그래밍을 하다보면 어쩔 수 없이 반복적으로 등장하는 코드들이 생기기 마련
- 로깅
- 트랜잭션 처리
- 보안 검사
- 이러한 중복되는 코드들을 하나의 모듈로 분리하여 관리하는 설계 방법이다
AOP 용어 정리
용어 | 설명 | 예시 (Spring AOP) |
Pointcut | 어드바이스가 적용될 지점을 정의하는 표현식. 메서드 실행 시점 등을 지정. | @Pointcut("execution(* com.example.service..*(..))") |
Advice | 실제로 수행되는 부가기능 로직. 아래 Before, After 등으로 세부 분류됨. | @Before("pointcut()") |
JoinPoint | 실제 AOP가 적용되는 구체적인 실행 지점. 메서드 실행, 생성자 호출 등. | JoinPoint joinPoint 파라미터로 메서드 정보 접근 |
Before Advice | 메서드 실행 전에 실행되는 부가기능. | @Before("pointcut()") |
After Advice | 메서드 실행이 끝난 직후 실행 (정상/예외 관계없이 무조건 실행). | @After("pointcut()") |
AfterReturning | 메서드가 정상적으로 끝난 후 실행. 리턴값을 가로챌 수 있음. | @AfterReturning(pointcut = "pointcut()", returning = "result") |
AfterThrowing | 메서드 실행 중 예외가 발생했을 때만 실행. | @AfterThrowing(pointcut = "pointcut()", throwing = "ex") |
Around Advice | 메서드 실행 전후 전체를 감쌈. 실행 여부도 제어 가능하며 가장 강력함. | @Around("pointcut()") |
Aspect | 포인트컷 + 어드바이스를 묶은 단위 모듈. | @Aspect 클래스 |
Weaving | 실제 코드에 AOP 기능이 적용되는 시점. (컴파일 타임, 로드 타임, 런타임 등) | 스프링 AOP는 런타임 위빙(프록시 기반) |
Target Object | AOP가 적용되는 실제 비즈니스 객체(빈). | ChannelServiceImpl 같은 클래스 |
AOP 적용하기 (프로젝트 리팩토링)
🖼️ AOP 다이어그램
🎯 기존 코드
Service 코드
- createChannel 메소드에는 channel을 생성하는 비즈니스 로직, 전달받은 인자를 확인하는 로깅 코드가 같이 있음
- OOP 관점으로 보았을 때 createChannel 메소드의 상관 없는 로깅 코드가 존재함
Application (현 프로젝트에서 Controller 역할)
- Controller에도 불필요한 메소드의 실행 결과를 확인하는 로깅 메소드들이 존재함
✅ AOP를 적용해 로깅 코드 분리
logging 클래스 정의
- @Pointcut("execution(* com.sprint.mission.discodeit.service..*(..))") 포인트컷 지정
- com.sprint.mission.discodeit.service 패키지 이하 모든 메소드 실행 시점에 적용
- @Before("serviceMethods()") serviceMethods의 포인트컷이 실행되기 전
- joinpoint를 통해 메소드 이름, 전달 받은 인자를 로깅
- @AfterReturning(pointcut = "serviceMethods()", returning = "result")
- 메소드가 실행되고난 후 메소드의 이름, 결과 값을 로깅
- @AfterThrowing(pointcut = "serviceMethods()", throwing = "ex")
- 메소드 실행 중 예외가 발생하였을 경우에만 예외 로깅
Service 코드 수정
- 전달받은 인자를 확인하는 로깅 코드 제거
Controller 코드
// 기존 코드
log("채널 생성", () -> channelService.createChannel(channelCreateDto));
// 수정한 코드
Channel channel = channelService.createChannel(channelCreateDto);
- AOP가 자동으로 실행 로그를 남기므로 기존 수동 로그 제거
✨ 결과
- ✅ 서비스 계층의 모든 메서드는 자동으로 실행 로그가 남음
- ✅ 서비스/컨트롤러의 중복 코드 제거 → 비즈니스 로직만 집중
- ✅ 유지보수성, 코드 가독성 향상
- 추후 Repository, Controller도 AOP 적용 예정
'Refactoring' 카테고리의 다른 글
Sprint Mission Part 3 File*Repository Refactoring (0) | 2025.04.30 |
---|---|
Sprint Mission Part-1 User ↔ Channel 구조, 양방향 의존을 UseCase로 리팩토링 (0) | 2025.04.08 |