공부한것들을 정리하는 블로그 입니다.
토비의스프링3.1 5장. 서비스 추상화 본문
토비의스프링 5장. 서비스 추상화
5.1 사용자 레벨 관리기능 추가하기
지금까지 다루었던 DAO는 단순 DB에 저장하고 불러오는 기능만을 담당했다. 간단한 비즈니스 로직을 추가하는 것이 이 장의 목표다.
ENUM
- 사용자 수정기능 추가
사용자 관리 로직은 어디에 두어야 할까?
- UserService 구현하기
- 유저 레벨 조작 구현하기
- 처음 가입한 회원은 BASIC 등급이어야 한다.
- 코드 리팩토링
- 업그레이드 가능한지 여부를 확인하는 메서드
- 실질적 레벨 업그레이드를 수행하는 메서드
5.2 트랜잭션 서비스 추상화
원본 코드를 수정하는 것은 좋은 생각이 아니다. 대신 UserService를 상속받고, upgradeLevel을 override하여 구현하면 장애상황에서의 대응을 테스트하는 좋은 UserService가 된다.
트랜잭션
- 롤백
- 커밋
JDBC의 트랜잭션
- autocommit 옵션
- try-catch : 트랜잭션 commit or rollback
첫 번째 아이디어 : 커넥션 관리를 UserService에 맡기기
upgradeLevels() 메서드 안에 커넥션의 종료와 시작을 수행해야 한다.
- Class UserService
- upgradeLevels 메서드 : Connection 객체 생성 후 try-catch문 안에서 upgradeLevel 메서드 호출
- upgradeLevel(Connection, User) 메서드 : userDao의 update 메서드 호출
- interface UserDao
- update(Connection, User) : DB를 업데이트하는 책임을 가지는 update 메서드를 가진다
- Class UserDaoJDBC implements UserDao
- update(Connection, User) : DI받은 Connection을 이용해 DB업데이트 역할을 수행하는 서비스로직 작성
=> 트랜잭션 문제는 해결되었으나, 추가 문제점 발생
- 템플릿 패턴(JdbcTemplate)을 사용하기 전으로 되돌아가서, JDBC API를 직접 사용하는 초기 방식
- UserService에서 DAO의 메소드와 비즈니스 로직의 파리미터에 Connection 이 추가되었기 떄문에
- upgradeLevels 메서드에서 호출하는 모든 메서드(upgradeLevel)에서 DB작업이 실행되기까지, 그 사이의 모든 메소드에 걸쳐서 Connection 오브젝트가 계속 전달되어야 한다.
- UserService는 스프링 빈으로 선언해서 싱글톤으로 되어 있으므로, 인스턴스 변수에 이 Connection을 저장해뒀다가 다른 메소드에서 재사용하는 것도 불가 (멀티스레드)
- UserDao 인터페이스 메소드에서 Connection 오브젝트를 파라미터로 가지게 된 순간, 결합도가 오르고 응집도가 낮아지고(안티패턴) DI를 적용한 내용이 쓸모없게 됨
두 번째 아이디어 : 독립적인 트랜잭션 동기화
DAO 메서드가 이 Connection을 사용하도록 한다.
- Connection 파라미터 제거
- 트랜젝션 동기화 관리자를 이용해 동기화 작업을 초기화
- DataSourceUtils에서 DB커넥션을 생성하고 트랜잭션을 시작
- 파라미터에서 Connection 제거 가능
멀티쓰레드 환경에서도 안전하기 트랜잭션 구현하기
- DataSource에서 직접 가져오는게 아닌, DataSource유틸리티를 만들어서 Connection을 획득하도록 작성함으로써 ThreadSafe한 저장소에 바인딩 구현
- 하나의 커넥션으로 반복적인 쿼리 실행
JdbcTemplate와 트랜잭션 동기화
- DataSource유틸리티를 통해 커넥션을 새로 생성했다면 새로운 커넥션을 쓰도록 구현
트랜젝션 서비스 추상화
- 기술과 환경에 종속되는 트랜젝션 경계설정 코드
시나리오 1
- 여러 DB를 하나의 트랜젝션에 처리하는 경우
- JDBC Connetion을 이용한 로컬 트랜젝션은 하나의 DB에 종속되기 때문에, 별도의 트랜젝션 관리자를 이용한 글로벌 트랜젝션 사용 필요
- JDBC 이외의 글로벌 트랜젝션을 제공하는 Java Transaction API가 있다.
- 트랜젝션 매니저는 DB와 각 서버를 제어하고 관리하는 리소스 매니저와 XA 프로토콜을 이용해 연결된다.
- 어플리케이션은 JTA를 통해 다수 DB와 서버를 관리할 수 있다.
5.3 서비스 추상화와 단일 책임 원칙
수평-수직 계층구조와 의존관계
- UserDao-UserService의 분리는 같은 계층에서 비즈니스 로직과 데이터 접근 로직을 분리한 수평적인 분리라면,
- 트랜잭션의 추상화는 애플리케이션 레벨의 로직과 로우레벨의 트랜잭션 기술에 독립적인 코드를 분리한 것이다.
단일 책임 원칙
5.4 메일 서비스 추상화
- UserService의 upgradeLevel()에 메일 발송 기능을 추가
악명높은 JavaMail의 설계
테스트와 서비스 추상화
- 스프링이 제공하는 MailSender를 구현한 추상화 클래스를 이용하면, JavaMail이 아닌 다른 메세징 서버 API를 이용하고자 할 때도 MailSender를 구현한 클래스를 만들어 DI해주면 끝나는 일이다.
- 만약 DB의 트랜젝션 개념을 메일에 적용한다면?
- 메일을 업그레이드할 유저 목록을 별도의 목록에 저장하고, 업그레이드 작업이 성공적으로 끝마쳤다면 한 번에 전송하도록 한다
- 유사 트랜잭션을 구현한다. send() 메서드를 호출하더라도 실제로 메일을 발송하지 않고 있다가, 작업이 끝나면 메일을 모두 발송하고, 예외가 발생한다면 메일 발송을 취소하는 방법으로 구현한다
테스트 대역
- 테스트 스텁(Test Stub)
- 테스트에 깊게 관여하는 테스트 대역
'Spring > 공부' 카테고리의 다른 글
토비의스프링3.1 9장. 스프링 프로젝트 시작하기 (0) | 2022.08.02 |
---|---|
토비의스프링3.1 8장. 스프링이란 무엇인가 (0) | 2022.07.30 |
토비의스프링3.1 7장. 스프링 핵심 기술의 응용 (0) | 2022.07.26 |
토비의스프링3.1 6장. AOP (0) | 2022.07.23 |
토비의스프링3.1 4장. 예외 (0) | 2022.07.19 |
토비의스프링3.1 3장. 템플릿 (0) | 2022.07.19 |
토비의스프링3.1 2장. 테스트 (0) | 2022.07.19 |
토비의스프링3.1 1장. 오브젝트와 의존관계 (0) | 2022.07.12 |