1. Advice 생명 주기
구분 | Per-Class (공유 인스턴스) |
Per-Instance (객체별 인스턴스)
|
적용 방식 | 모든 대상 객체에서 동일한 Advice 인스턴스 공유 |
각 대상 객체마다 별도의 Advice 인스턴스 생성
|
상태 관리 | Stateless | Stateful |
사용 사례 | - 트랜잭션 관리 - 로깅 - 보안 검사 |
- Mixin 패턴 구현
- Introduction (인터페이스 동적 추가) |
성능 | 메모리 사용량이 적고 효율적 |
객체마다 인스턴스 생성 → 메모리 오버헤드 가능성
|
대상 | 모든 메서드 호출에 공통 적용 |
특정 객체에 한정된 확장 기능 적용
|
Spring AOP 지원 | 기본 방식 (JDK 동적 프록시/CGLIB) |
@Aspect(perthis, pertarget)
|
2. Advice 유형
Advice 종류 | 실행 시점 | 반환값 변경 | 예외 처리 | 사용 목적 / 특징 |
Around Advice (MethodInterceptor) |
실행 전/후/예외 시 | ✅ | ✅ | 메서드 실행 전후, 예외 모두 제어 |
Before Advice (MethodBeforeAdvice) |
메서드 실행 전 | ❌ | ✅ | 메서드 실행 전 검증, 로깅 등 사전 처리 |
After Returning (AfterReturningAdvice) |
정상 종료 후 | ❌ | ❌ | 반환값 로깅, 통계 등 |
Throws Advice (ThrowsAdvice) |
예외 발생 시 | ❌ | ✅ | 예외 처리 및 예외 로깅 |
Introduction Advice (IntroductionInterceptor) (IntroductionAdvisor) |
런타임 시 인터페이스 주입 |
❌ | ❌ | 새로운 인터페이스/기능(Mixin) 동적 추가 |
예제) Around Advice
더보기
더보기
public class DebugInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("Before: " + invocation);
Object result = invocation.proceed(); // 실제 메서드 실행
System.out.println("After");
return result;
}
}
예제) Before Advice
더보기
더보기
public class DebugInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("Before: " + invocation);
Object result = invocation.proceed(); // 실제 메서드 실행
System.out.println("After");
return result;
}
}
예제) After Returning
더보기
더보기
public class CountingAfterReturningAdvice implements AfterReturningAdvice {
private int count;
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
count++;
}
public int getCount() { return count; }
}
예제) Throws Advice
더보기
더보기
public class IllegalArgumentExceptionThrowsAdvice implements ThrowsAdvice {
public void afterThrowing(IllegalArgumentException ex) {
System.out.println("exception!");
System.out.println(ex.getMessage());
}
public void afterThrowing(Method m, Object[] args, Object target, IllegalArgumentException ex) {
System.out.println("exception!");
System.out.println("[method] " + m.getName());
System.out.println("[args] ");
for (Object arg : args) System.out.println(" - " + arg);
System.out.println("[object] " + target.getClass().getName());
System.out.println("[exception message] " + ex.getMessage());
}
}
예제) Introduction Advice
더보기
더보기
public interface Lockable {
void lock();
void unlock();
boolean locked();
}
public class LockMixin extends DelegatingIntroductionInterceptor implements Lockable {
private boolean locked;
@Override
public void lock() {
this.locked = true;
}
@Override
public void unlock() {
this.locked = false;
}
@Override
public boolean locked() {
return this.locked;
}
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
if (locked() && invocation.getMethod().getName().startsWith("set")) throw new LockedException();
return super.invoke(invocation);
}
class LockedException extends RuntimeException {}
}
public class LockMixinAdvisor extends DefaultIntroductionAdvisor {
public LockMixinAdvisor() {
super(new LockMixin(), Lockable.class);
}
}
MyService original = new MyService();
ProxyFactory pf = new ProxyFactory(original);
pf.addAdvisor(new DefaultIntroductionAdvisor(new LockMixin(), Lockable.class));
Object proxy = pf.getProxy();
((MyService) proxy).doWork(); // 원래 기능
((Lockable) proxy).lock(); // 새로 추가된 기능!
System.out.println(((Lockable) proxy).isLocked()); // true
- 프록시에 Advisor를 주입하면서 새로운 인터페이스까지 도입함
- 마치 원래 객체가 그 인터페이스를 구현한 것처럼 보이게 만듬
출처
'Spring > Spring' 카테고리의 다른 글
[Spring][AOP] 3. Advisor API (0) | 2025.04.09 |
---|---|
[Spring][AOP] 2. Pointcut API (1) | 2025.04.09 |
[Spring][Validation] 2. Java Bean Validation (0) | 2025.04.06 |
[Spring][Validation] 1. Validator Interface (0) | 2025.04.06 |
[Spring][Object] 1. Data Binding (0) | 2025.04.06 |