Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
Tags
- Si
- 스프링
- 백엔드
- spring aop
- spring
- 엘라스틱서치
- 비전공개발자
- 프론트엔드
- 일감관리
- PM
- 개발자
- 검색
- 자바
- elasticsearch
- 웹프론트
- Database
- 인덱스
- 데이터베이스
- redmine
- 오라클
- frontend
- 레드마인
- 프로젝트관리
- AOP
- PreparedStatement
- It
- db
- 이슈관리
- kibana
- java
Archives
- Today
- Total
리타의 저장소
Spring AOP | @Transactional과 self-invocation 문제 본문

Class 안에서 this.메서드() 호출하는 경우 AOP 작동할까?
Q. 아래와 같은 코드에서, 과연 @Transactional이 제대로 동작할까??
@Component
@RequiredArgsConstructor
public class OrderApplication {
private final OrderService orderService;
private final OrderResultPublisher publisher;
public void orderGenerateWithPublish(OrderVo orderVo) {
OrderMessage message = this.generateOrder(orderVo);
// 비동기 Queue 발행
publisher.send(message);
}
@Transactional
public OrderMessage generateOrder(OrderVo orderVo) {
// 중복 주문제거
if (orderService.existsByOrderNumber(orderVo.getOrderNumber())) {
orderService.deleteByOrderNumber(orderVo.getOrderNumber());
}
Order order = orderService.save(orderVo.toEntity());
return OrderMessage.from(order);
}
}
❌ 정답: AOP는 작동하지 않는다.
Self-invocation 문제에 직면하게 된다. 프록시 기반 으로 동작하는 Spring AOP. 내부 메서드는 프록시 객체가 아니라 this 자신을 통해 직접 호출되기 때문에, 프록시를 타지 않는다. 이걸 해결하고 싶다면, 대상 메서드를 다른 Bean으로 분리하면 된다.
self-invocation 문제
Spring AOP는 프록시 기반이다. 그러니까, 메서드 호출이 프록시 객체를 거쳐 이뤄져야 AOP가 적용된다는 소리이다.
하지만, 위 코드 처럼, this.generateOrder()를 하게 되는 경우 자신(this)을 통해 직접 호출되기 떄문에, 프록시 객체를 거치지 않게되고, AOP가 적용되지 않는다.
// 이 호출은 프록시가 개입하지 않음 ❌
OrderMessage message = this.generateOrder(orderVo);
그럼, AOP를 타게 만드려면 어떻게 해야할까 ?
- generateOrder를 별도 @Component로 분리
- AspectJ (Compile-time 또는 Load-time weaving) 사용→ 다만, 설정이 복잡하고 유지보수가 어렵다.
번외 : AspectJ ? @Aspect는 다른걸까?
@Aspect는 같으나, “동작방식”은 다르다. Spring AOP에서도 @Aspect, @Before, @Around 등을 사용한다. 이건 AspectJ의 문법을 그대로 가져온 것일 뿐, 실제 AspectJ의 엔진을 사용하는 것은 아니다.
Spring AOP의 위빙 방식은, 프록시 기반 (런타임 위빙) 이고,
AspectJ의 위빙 방식은, 바이트코드 기반 (컴파일/로드타임 위빙) 이다.
컴파일 시점, 클래스 로딩 시점에 Advice를 삽입한다는 점에서, AspectJ를 사용하게 되는 경우, 내부 호출도 감지하게 될 수 있는 것.
그러니까 :
둘 다 바이트코드 조작은 하지만, Spring AOP는 바깥에 프록시 껍데기를 덧씌우고, AspectJ는 내부를 직접 편집한다.
CGLIB: ProxyClass extends TargetClass { ... } 를 만들어서 오버라이드 → 우회 방식
AspectJ: .class 파일 내부에 직접 advice 코드를 삽입 → 직접 방식
'Dev > Backend' 카테고리의 다른 글
| Presigned Url, Signed Url, Signed Cookie (1) | 2026.03.02 |
|---|---|
| GC의 종류 & 운영중인 시스템의 GC 확인하기 (0) | 2025.10.11 |
| Spring AOP | 돌고돌아 JDK Dynamic Proxy vs CGLIB Proxy (0) | 2025.10.11 |
| Spring AOP | CGLIB Proxy (0) | 2025.10.11 |
| Spring AOP | JDK Dynamic Proxy (0) | 2025.10.11 |