| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
| 29 | 30 | 31 |
- junit
- list
- 정규식
- CSS
- 자바스크립트
- 인텔리제이
- 단위테스트
- vscode
- Visual Studio Code
- js
- Java
- SpringBoot
- Array
- input
- string
- Eclipse
- 배열
- junit5
- 테스트자동화
- 자바
- 문자열
- html
- math
- 자바문법
- IntelliJ
- javascript
- ArrayList
- HashMap
- java테스트
- 스프링부트
- Today
- Total
어제 오늘 내일
[Spring Boot] "복사-붙여넣기 멈춰!" AOP로 중복 코드 싹둑 자르기 (feat. 실행 시간 측정) 본문
[Spring Boot] "복사-붙여넣기 멈춰!" AOP로 중복 코드 싹둑 자르기 (feat. 실행 시간 측정)
hi.anna 2026. 3. 16. 10:39
여러분, 혹시 이런 코드를 짜보신 적 있나요?
public void join(Member member) {
long start = System.currentTimeMillis(); // 1. 시작 시간 측정
try {
memberRepository.save(member); // 핵심 로직 (이거 하나만 진짜임!)
} finally {
long finish = System.currentTimeMillis(); // 2. 종료 시간 측정
long timeMs = finish - start;
System.out.println("join = " + timeMs + "ms"); // 3. 로그 출력
}
}
회원 가입, 조회, 수정... 모든 메서드마다 저 시간 측정 코드(1, 2, 3번)를 넣어야 한다면? 끔찍합니다. 핵심 로직이 눈에 들어오지도 않죠.
이때 필요한 것이 바로 AOP(Aspect Oriented Programming)입니다.
1. AOP가 뭔가요? (핵심 관심사 vs 공통 관심사)
AOP는 프로그램을 두 가지 관점으로 바라봅니다.
- 핵심 관심사 (Core Concern): 우리가 진짜 하고 싶은 일 (회원 가입, 주문, 결제 등)
- 공통 관심사 (Cross-cutting Concern): 여러 곳에서 공통적으로 쓰이는 일 (로그, 보안, 트랜잭션 등)
AOP는 이 공통 관심사를 따로 떼어내서 관리하고, 실행할 때 원하는 곳에 자동으로 적용해 주는 기술입니다. 마치 샌드위치의 빵(공통)과 속재료(핵심)를 따로 준비하는 것과 같습니다.
2. AOP 용어 정리 (면접 필수!)
AOP를 쓰려면 용어 4가지만 알면 됩니다. (조금 어렵지만 중요해요!)
- Aspect (관점): 공통 관심사 그 자체. (예:
LogAspect클래스) - Advice (조언): "언제, 무엇을 할 거야?" (예: 메서드 실행 전에 로그를 남겨라)
- Pointcut (포인트컷): "어디에 적용할 거야?" (예:
com.example.service패키지 하위의 모든 메서드) - JoinPoint (조인포인트): 적용 가능한 지점. (메서드 실행 시점, 생성자 호출 시점 등)
3. 실전 예제: 어노테이션 하나로 실행 시간 측정하기
가장 많이 쓰는 예제입니다. @LogExecutionTime이라는 어노테이션을 붙이면 자동으로 실행 시간을 찍어주는 AOP를 만들어보겠습니다.
① 커스텀 어노테이션 만들기
@Target(ElementType.METHOD) // 메서드에 붙일 거야
@Retention(RetentionPolicy.RUNTIME) // 런타임까지 유지할 거야
public @interface LogExecutionTime {
}
② Aspect 구현하기 (여기가 핵심!)
@Slf4j
@Aspect // 1. AOP 클래스다!
@Component // 빈으로 등록해야 함
public class LogTraceAspect {
// 2. Pointcut: @LogExecutionTime 어노테이션이 붙은 곳에 적용해라
@Around("@annotation(LogExecutionTime)")
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
log.info("START: {}", joinPoint.toString()); // 메서드 시작 로그
try {
// 3. ★ 핵심 로직 실행! (join.proceed()가 실제 메서드를 호출함)
return joinPoint.proceed();
} finally {
long finish = System.currentTimeMillis();
long timeMs = finish - start;
log.info("END: {} {}ms", joinPoint.toString(), timeMs); // 종료 및 시간 로그
}
}
}
③ 사용하기
이제 비즈니스 로직은 아주 깨끗해집니다. 어노테이션 하나만 붙이면 되니까요!
@Service
public class MemberService {
@LogExecutionTime // 이제 이 메서드는 실행 시간이 자동 측정됩니다.
public Long join(Member member) {
memberRepository.save(member);
return member.getId();
}
}
4. AOP 동작 원리: 프록시(Proxy)
"도대체 코드를 안 고쳤는데 어떻게 중간에 끼어드는 거죠?"
스프링 AOP는 프록시(Proxy) 패턴을 사용합니다.
- 스프링이 실행될 때,
MemberService빈(Bean)을 만듭니다. - 이때 AOP가 적용된 클래스라면, 스프링은 가짜(Proxy) MemberService를 만들어서 갈아끼웁니다.
- 클라이언트가
join()을 호출하면 -> 가짜가 먼저 받아서 시간을 측정하고 -> 진짜join()을 호출합니다.
5. Interceptor vs AOP: 뭐가 달라요?
지난 시간에 배운 인터셉터와 헷갈리시죠? 결정적인 차이가 있습니다.
| 구분 | Interceptor (인터셉터) | AOP(관점 지향) |
| 적용 대상 | URL (웹 요청) | 메서드 (Service, Repository 등) |
| 파라미터 | Request, Response 객체 |
메서드의 매개변수 (Object[] args) |
| 주 사용처 | 로그인 체크, 권한 인증 | 트랜잭션, 로깅, 실행 시간 측정 |
| 특징 | 컨트롤러 앞뒤만 가능 | 어디든 원하는 메서드에 적용 가능 |
결론: 웹과 관련된 공통 처리는 Interceptor, 비즈니스 로직의 공통 처리는 AOP를 쓰세요.
마치며
오늘의 결론입니다.
- AOP는 핵심 로직에서 공통 로직(로그, 트랜잭션 등)을 분리하는 기술이다.
@Aspect,@Around,ProceedingJoinPoint세 가지만 기억하면 구현할 수 있다.- 스프링 AOP는 프록시(Proxy)를 통해 동작한다.
이제 여러분의 코드는 군더더기 없이 비즈니스 로직에만 집중할 수 있게 되었습니다.
다음 포스팅에서는 개발이 다 끝났으니 배포를 해야겠죠? "Jar 파일 하나면 끝!" Gradle 빌드 도구와 실행 가능한 Jar(Executable Jar) 만들기에 대해 알아보겠습니다.
