개발일기/CS(면접)
Spring AOP 란?
w.llama
2024. 8. 12. 21:02
Spring AOP란?
Spring AOP는 관점 지향 프로그래밍을 구현한 것으로, 애플리케이션의 여러 부분에 걸쳐 나타나는 공통 관심사를 모듈화하여 코드의 중복을 줄이고 유지보수성을 향상시키는 프로그래밍 패러다임이다.
주요 용도:
- 로깅
- 보안
- 트랜잭션 관리
- 성능 모니터링
AOP 핵심 개념
Aspect
- 여러 객체에 공통으로 적용되는 기능을 모듈화한 것
- 예: 로깅 Aspect, 보안 Aspect
Join Point
- Aspect를 적용할 수 있는 지점
- Spring AOP에서는 메서드 실행 지점만 Join Point로 사용
Pointcut
- Join Point의 부분 집합으로, 실제로 Aspect를 적용할 지점을 선별
- 예: "get"으로 시작하는 모든 메서드에 적용
Advice
- Aspect가 실제로 수행하는 작업과 그 시점을 정의
- 주요 타입:
- Before: 메서드 실행 전
- After: 메서드 실행 후 (결과에 상관없이)
- After-returning: 메서드가 정상적으로 결과를 반환한 후
- After-throwing: 메서드가 예외를 던진 후
- Around: 메서드 실행 전과 후
Weaving
- Aspect를 대상 객체에 적용하여 새로운 프록시 객체를 생성하는 과정
Spring AOP의 특징
- 프록시 기반 AOP
- 대상 객체를 감싸는 프록시 객체를 생성하여 AOP를 구현
- 메서드 조인 포인트만 지원
- 메서드 실행 시점에만 Aspect 적용 가능
- 필드 접근, 객체 생성 등의 조인 포인트는 지원하지 않음
- 런타임 Weaving
- 애플리케이션 실행 중에 프록시 객체 생성 및 Aspect 적용
- Spring 컨테이너와의 통합
- Spring의 IoC 컨테이너와 완벽하게 통합되어 사용 용이
Spring AOP 사용 예시
@Aspect
@Component
public class ValidBindingResultAop {
@Pointcut("execution(* com.sparta.ottoon.auth.controller.UserController.*(..))")
private void auth() {}
@Before("auth() && args(requestDto, bindingResult)")
public void handleBindingResult(SignupRequestDto requestDto, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
List<FieldError> fieldErrors = bindingResult.getFieldErrors();
for (FieldError fieldError : fieldErrors) {
// 로깅 또는 원하는 처리 수행
System.out.println("BindingResult Error: " + fieldError.getField() + " - " + fieldError.getDefaultMessage());
}
throw new CustomException(ErrorCode.FAIL);
}
}
}
Spring AOP의 장단점
장점
- 코드 중복 감소
- 비즈니스 로직과 공통 관심사의 분리
- 유지보수성 향상
- 모듈화를 통한 재사용성 증가
단점
- 런타임 시 약간의 성능 오버헤드
- 복잡한 AOP 설정은 코드 이해도를 낮출 수 있음
- 메서드 조인 포인트로 제한된 기능
Spring AOP 관련 주요 어노테이션
@Aspect
- 해당 클래스가 Aspect임을 나타냄
- Aspect 클래스에 사용됨
@Aspect
@Component
public class LoggingAspect {
// Aspect 내용
}
@Pointcut
- Pointcut을 정의
- 메서드 시그니처와 함께 사용되며, 실제 메서드 본문은 비워둔다.
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceLayer() {}
@Before
- 대상 메서드 실행 전에 실행될 Advice를 정의
@Before("serviceLayer()")
public void logBefore(JoinPoint joinPoint) {
// 메서드 실행 전 로직
}
@After
- 대상 메서드 실행 후에 실행될 Advice를 정의
- 메서드의 정상 종료나 예외 발생 여부와 관계없이 실행
@After("serviceLayer()")
public void logAfter(JoinPoint joinPoint) {
// 메서드 실행 후 로직
}
@AfterReturning
- 대상 메서드가 정상적으로 결과를 반환한 후에 실행될 Advice를 정의
@AfterReturning(pointcut = "serviceLayer()", returning = "result")
public void logAfterReturning(JoinPoint joinPoint, Object result) {
// 메서드가 정상적으로 결과를 반환한 후 로직
}
@AfterThrowing
- 대상 메서드에서 예외가 발생했을 때 실행될 Advice를 정의
@AfterThrowing(pointcut = "serviceLayer()", throwing = "ex")
public void logAfterThrowing(JoinPoint joinPoint, Exception ex) {
// 메서드에서 예외 발생 시 로직
}
@Around
- 대상 메서드 실행 전후에 실행될 Advice를 정의
- 가장 강력한 Advice로, 메서드 실행을 완전히 제어할 수 있음
@Around("serviceLayer()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
// 메서드 실행 전 로직
Object result = joinPoint.proceed(); // 실제 메서드 실행
// 메서드 실행 후 로직
return result;
}
@EnableAspectJAutoProxy
- Spring AOP 지원을 활성화
- 주로 설정 클래스에서 사용
@Configuration
@EnableAspectJAutoProxy
public class AopConfig {
// AOP 설정
}
어노테이션 사용 시 주의사항
- 성능 고려: 과도한 AOP 사용은 애플리케이션 성능에 영향을 줄 수 있다.
- 가독성: 너무 많은 Aspect를 사용하면 코드 흐름을 파악하기 어려울 수 있다.
- 순서 관리: 여러 Advice가 동일한 Join Point에 적용될 때는 실행 순서를 관리해야 한다.
- 프록시 제한사항: 자기 호출(self-invocation)에는 AOP가 적용되지 않는다.