AOP(Aspect-Oriented Programming)와 단순히 공통 메서드를 분리하는 방법은 기능적으로 비슷해 보일 수 있지만, 관점 지향 프로그래밍(AOP)이 제공하는 강력한 이점이 있는 방식이다.
| AOP (Aspect-Oriented Programming) | 공통 메서드 분리 (OOP 방식) | |
|---|---|---|
| 적용 방식 | 어노테이션이나 포인트컷을 사용하여 특정 메서드에 자동 적용되는 방식 | 직접 메서드를 호출해야 하는 방식 |
| 침투성 | 기존 비즈니스 로직 코드에 전혀 영향을 주지 않는 방식 | 해당 메서드를 명시적으로 호출해야 하는 방식 |
| 관심사 분리 (Separation of Concerns) | 핵심 비즈니스 로직과 부가 로직을 완전히 분리하는 방식 | 부가 로직이 핵심 로직과 혼재될 가능성이 높은 방식 |
| 유지보수성 | 새로운 기능 추가 시 기존 코드 수정 없이 Aspect만 변경하면 되는 방식 | 모든 호출 부분을 찾아 수정해야 하는 방식 |
| 적용 범위 | 전역적으로 특정 로직을 적용할 수 있는 방식 (@Around, @Before, @After 등) | 적용하려면 개별 메서드에서 직접 호출해야 하는 방식 |
| 성능 | 런타임에서 Proxy 기반으로 동작하는 방식 (성능 영향이 있음) | 메서드 호출 방식이므로 성능 영향이 적은 방식 |
AOP는 반복적으로 사용되는 부가 기능(관점, Aspect)을 비즈니스 로직과 완전히 분리하는 방식이다.
로깅 (Logging)
트랜잭션 관리 (Transaction Management)
@Transactional 같은 어노테이션을 이용하여 트랜잭션을 자동 관리하는 방식 보안 (Security)
@PreAuthorize, @CheckMembership 등) 예외 처리 (Exception Handling)
캐싱 (Caching)
모니터링 (Monitoring & Metrics)
💡 @CheckMembership을 통해 프리미엄 유저가 아닐 경우 특정 데이터를 마스킹하는 방식
@Around(value = "@annotation(com.example.connect.global.aop.annotation.CheckMembership) && args(userId, id)",
argNames = "joinPoint,userId,id")
public Object checkMembership(ProceedingJoinPoint joinPoint, Long userId, Long id) throws Throwable {
Object result = joinPoint.proceed();
if (!MembershipType.PREMIUM.equals(getCurrentUser().getMembershipType())) {
if (result instanceof UserImageDetailResDto) {
return maskUserImageDetailResDto((UserImageDetailResDto) result);
}
}
return result;
}
✅ AOP를 적용하면 코드에 @CheckMembership만 붙이면 되는 방식
✅ 모든 API에서 이 로직을 자동으로 실행하여 비즈니스 로직과 분리되는 방식
💡 checkMembership을 직접 호출해야 하는 방식
public UserImageDetailResDto getUserImage(Long userId, Long id) {
UserImageDetailResDto result = userImageService.getImageById(userId, id);
if (!MembershipType.PREMIUM.equals(getCurrentUser().getMembershipType())) {
return maskUserImageDetailResDto(result);
}
return result;
}
✅ 비즈니스 로직 안에서 직접 메서드를 호출해야 하는 방식
❌ 매번 checkMembership()을 호출해야 해서 코드가 중복될 가능성이 높은 방식
❌ 다른 API에서 적용하려면 동일한 로직을 매번 추가해야 하는 방식
@CheckMembership 어노테이션만 추가하면 자동 적용되므로 비즈니스 로직이 깔끔하게 유지되는 방식이다.@Before, @Around 등으로 실행 위치를 선택할 수 있는 방식**이다.@CheckMembership만 붙이면 동일한 로직을 적용할 수 있어 유지보수가 용이한 방식이다.➡ 단순한 코드 재사용이라면 "공통 메서드 분리"가 적합한 방식이다.
➡ 하지만 전역적으로 특정 로직을 자동 실행해야 한다면 "AOP"가 훨씬 유리한 방식이다! 🚀