반응형
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
- 소프티어
- 기술면접
- 물채우기
- 백트래킹
- 백준
- 파라메트릭
- 6987
- BOJ
- 매개변수탐색
- 퇴사통보
- boj #19237 #어른 상어
- @P0
- dfs
- 처우협의
- Docker
- 연결요소
- 처우산정
- Kafka
- softeer
- 오퍼레터
- 경력
- compose
- 이분탐색
- BFS
- 성적평가
- msSQL
- OFFSET
- upper_bound
- incr
- 13908
Archives
- Today
- Total
기술 블로그
@Transactional과 프록시 패턴의 관계 본문
728x90
반응형
@Transactional과 프록시 패턴의 관계
@Transactional의 동작 방식을 프록시 패턴과 연결해서 설명해드리겠습니다.
프록시 패턴 기본 개념
프록시 패턴은 실제 객체를 대신하는 대리자(프록시) 객체를 사용하여:
- 실제 객체에 대한 접근을 제어하고
- 추가 기능을 제공하는 디자인 패턴입니다.
@Transactional과 프록시 패턴의 연결점
스프링에서 @Transactional을 사용하면 다음과 같은 일이 발생합니다:
- 스프링은 원본 객체를 감싸는 프록시 객체를 생성합니다
- 이 프록시는 실제 메소드 실행 전후에 트랜잭션 관련 코드를 추가합니다
- 클라이언트는 원본 객체 대신 이 프록시와 상호작용합니다
동작 과정 상세 설명
- 프록시 생성:
- 스프링 컨테이너는 빈 초기화 시 @Transactional 애노테이션을 감지
- 해당 빈에 대한 프록시 객체를 생성 (JDK 동적 프록시 또는 CGLIB)
- 원본 빈 대신 프록시 객체를 컨테이너에 등록
- 메서드 호출 가로채기:
- 클라이언트가 서비스 메서드를 호출하면 먼저 프록시 객체의 메서드가 호출됨
- 프록시는 @Transactional 속성(전파 방식, 격리 수준, 타임아웃 등)을 확인
- 트랜잭션 시작:
- 프록시는 PlatformTransactionManager를 통해 트랜잭션을 시작
- 트랜잭션 정보를 ThreadLocal에 저장하여 동일 스레드에서 접근 가능하게 함
- 원본 메서드 실행:
- 프록시가 실제 비즈니스 로직을 수행하는 원본 객체의 메서드를 호출
- 트랜잭션 종료:
- 정상 실행 시: 트랜잭션 커밋
- 예외 발생 시: 롤백 대상 예외인지 확인 후 롤백 (기본적으로 RuntimeException과 Error만 롤백)
- 트랜잭션 리소스 정리 (데이터베이스 연결 반환 등)
예시 코드로 보는 @Transactional 동작 방식
1. 원본 서비스 클래스
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Transactional
public void createUser(User user) {
userRepository.save(user);
// 다른 로직들...
}
}
2. 스프링이 내부적으로 생성하는 프록시 (개념적 코드)
public class UserServiceProxy extends UserService {
private UserService target; // 실제 UserService
private PlatformTransactionManager transactionManager;
public UserServiceProxy(UserService target, PlatformTransactionManager transactionManager) {
this.target = target;
this.transactionManager = transactionManager;
}
@Override
public void createUser(User user) {
// 트랜잭션 시작
TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
try {
// 실제 비즈니스 로직 수행
target.createUser(user);
// 트랜잭션 커밋
transactionManager.commit(status);
} catch (Exception e) {
// 예외 발생 시 롤백
transactionManager.rollback(status);
throw e;
}
}
}
3. 실제 사용 예시
@RestController
public class UserController {
private final UserService userService; // 실제로는 UserServiceProxy가 주입됨!
public UserController(UserService userService) {
this.userService = userService;
}
@PostMapping("/users")
public ResponseEntity<Void> createUser(@RequestBody User user) {
userService.createUser(user); // 프록시의 메서드가 호출됨
return ResponseEntity.ok().build();
}
}
@Transactional 동작 흐름도
┌─────────────────┐ 1. 메서드 호출 ┌──────────────────────┐
│ │─────────────────────▶│ │
│ 클라이언트 │ │ @Transactional │
│ (Controller) │ │ 프록시 객체 │
│ │◀─────────────────────│ │
└─────────────────┘ 8. 결과 반환 └──────────────────────┘
│ ▲
2. 트랜잭션 시작 │ │ 7. 트랜잭션 완료
▼ │
┌──────────────────────┐
│ │
│ PlatformTransaction │
│ Manager │
│ │
└──────────────────────┘
│ ▲
3. 트랜잭션 컨텍스트 생성 │ │ 6. 커밋/롤백
▼ │
4. 메서드 호출 ┌──────────────────────┐
┌───────────────────▶│ │
│ │ 실제 서비스 객체 │
│ │ (UserServiceImpl) │
│ │ │
│ └──────────────────────┘
│ │
│ 5. DB 작업 실행 ▼
│ ┌──────────────────────┐
│ │ │
└────────────────────│ Database │
│ │
└──────────────────────┘
프록시 패턴을 활용한 @Transactional의 주요 흐름은 다음과 같습니다:
- 클라이언트(Controller)는 서비스 메서드를 호출하지만, 실제로는 프록시 객체의 메서드가 호출됩니다.
- 프록시는 TransactionManager를 통해 트랜잭션을 시작합니다.
- 트랜잭션 컨텍스트가 생성되고 현재 스레드에 바인딩됩니다.
- 프록시는 실제 서비스 객체의 메서드를 호출합니다.
- 서비스 객체는 데이터베이스 작업을 수행합니다.
- 작업이 완료되면 프록시로 제어가 돌아오고, 예외 발생 여부에 따라 커밋 또는 롤백됩니다.
- TransactionManager가 트랜잭션을 완료합니다.
- 프록시는 결과를 클라이언트에 반환합니다.
728x90
반응형
'JAVA' 카테고리의 다른 글
@Transactional 어노테이션의 역할과 의미 (0) | 2025.04.23 |
---|---|
CountDownLatch (0) | 2025.04.10 |
Executors.newFixedThreadPool() (0) | 2025.04.10 |
직렬화(Serialization)와 역직렬화(Deserialization), transient 변수 (0) | 2023.09.07 |
어노테이션(Annotation) (0) | 2020.06.07 |