레이어드 아키텍처(Layered Architecture) 란?
컨트롤러와 서비스
- 쇼핑몰에서 게시판에서도 회원 정보를 보여주고, 상품 목록 보기에서도 회원 정보를 보여줘야 한다면, 해당 코드를 별도의 객체인 서비스로 구현하는 것이 좋다.
- 서비스 객체는 보통 업무와 관련된 메서드를 가지고 있다. 이것들을 비즈니스 메서드라고 부른다.
- 비지니스 메소드를 별도의 service 객체에서 구현하도록 하고 컨트롤러는 service 객체를 사용하도록 한다.
서비스 객체
- 비즈니스 로직을 수행하는 메소드를 가지고 있는 객체를 서비스 객체라고 한다.
- 보통 하나의 비지니스 로직은 하나의 로직으로 동작한다.
트랜잭션
트랜잭션의 특징
원자성 (Atomicity)
- 전체가 성공하거나 전체가 실패하는 것을 의미한다.
- 출금이라는 기능의 흐름이 다음과 같다고 생각해보자
- 잔액 조회
- 출금 금액이 잔액보다 작은지 검사
- 작다면 잔액을 출금액을 뺀 금액으로 수정한다.
- 언제, 어디서 출금했는지 정보를 기록한다.
- 사용자에게 출금한다.
- 만약 중간에 오류가 발생한다면, 그동안의 작업을 모두 원래대로 복원을 해야한다. 이를 rollback이라고 한다.
- 모두 성공했다면 정보를 반영해야 한다. 이를 commit이라고 한다.
- 이렇게 rollback 하거나 commit을 하게 되면 하나의 트랜잭션 처리가 완료된다.
일관성 (Consistency)
- 트랜잭션의 작업 처리 결과가 항상 일관성이 있어야 한다.
- 트랜잭션이 진행되는 동안 데이터가 변경되더라도 처음에 트랜잭션을 진행하기 위해 참조한 데이터로 진행한다.
- 이렇게 함으로써 각 사용자는 일관성 있는 데이터를 볼 수 있다.
독립성 (Isolation)
- 둘 이상의 트랜잭션이 동시에 병행 실행되고 있는 경우에 어느 하나의 트랜잭션이라도 다른 트랜잭션의 연산에 끼어들 수 없다.
- 하나의 특정 트랜잭션이 완료될 때까지, 다른 트랜잭션이 특정 트랜잭션의 결과를 참조할 수 없다.
지속성 (Durability)
- 트랜잭션이 성공적으로 완료되었을 경우, 결과는 영구적으로 반영되어야 한다.
JDBC 프로그래밍에서 트랜잭션 처리 방법
- DB에 연결된 후 Connection 객체의 setAutoCommit 메소드에 false를 파라미터로 지정한다.
- setAutoCommit의 디폴트는 true로 되어있어서 입력, 수정, 삭제를 하면 별도로 commit 명령을 수행하지 않아도 바로 데이터베이스에 반영된다.
- 입력, 수정, 삭제 sql이 실행을 한 후 모두 성공했을 경우 Connection이 가지고 있는 commit() 메소드를 호출한다.
@EnableTransactionManagement
- Spring Java Config 파일에서 트랜잭션을 활성화 할 때 사용할 수있는 어노테이션이다.
- Java Config를 사용하게 되면 PlatformTransactionManager 구현체를 모두 찾아서 그 중에 하나를 매핑해 사용한다.
- 특정 트랜잭션 매니저를 사용하고자 한다면, TransactionManagementConfigurer를 Java Config 파일에서 구현하고 원하는 트랜잭션 매니저를 리턴하도록 한다.
- 아니면, 특정 트랜잭션 매니저 객체를 생성시 @Primary 어노테이션을 지정한다.
서비스 객체에서 중복으로 호출되는 코드의 처리
- 서비스 객체들마다 비즈니스 메서드를 가지고 있고, 이 하나의 비즈니스 메서드는 트랜잭션 단위로 보통 작업이 처리가 된다.
- 하나의 트랜잭션에는 여러 개의 DB 작업이 수행될 수도 있다.
이 때, 메서드마다 중복되는 기능을 호출하는 경우도 있는데, 이런 부분을 별도의 객체나 메서드로 분리해서 사용해야 한다.
- Presentation Layer에서는 컨트롤러 객체가 동작을 한다.
- 이 부분이 웹에서 보여진다.
- 앱, window 등에서 보여지게 하려면 해당 계층만 바꿔주면 된다. 때문에 설정 파일들도 분리하는 것이 좋다.
- Service Layer에서는 비즈니스 메서드를 가지고 있는 서비스 객체가 동작한다.
- Repository Layer에서는 실제 데이터 베이스에 접근해서 데이터를 가져오는 일과 같은 것들만 수행한다.
- 데이터 액세스 메소드를 별도의 Repository(Dao) 객체에서 구현하도록 하고 Service는 Repository 객체를 사용하도록 한다.
설정의 분리
- Spring 설정 파일을 프레젠테이션 레이어쪽과 나머지를 분리할 수 있다.
- web.xml 파일에서 프리젠테이션 레이어에 대한 스프링 설정을 DispatcherServlet이 읽도록 하고, 그 외의 설정은 ContextLoaderListener를 통해 읽도록 한다.
- Dispatcher Servlet을 경우에 따라서 2개 이상 설정할 수 있는데, 이 경우에 각각의 dispatcherServlet의 ApplicationContext가 각각 독립적이기 때문에 각각의 설정 파일에서 생성한 빈을 서로 사용할 수 없다.
- 같이 동시에 필요한 빈은 ContextLoaderListener를 사용함으로써 공통으로 사용할 수 있다.
- ContextLoaderListener와 DispatcherServlet은 각각 ApplicationContext를 생성하는데, ContextLoaderListener가 생성하는 ApplicationContext가 root 컨텍스트가 되고 DispatcherServlet이 생성한 인스턴스는 root 컨텍스트를 부모로하는 자식 컨텍스트가 된다.
- 자식 컨텍스트들은 root 컨텍스트의 설정 빈을 사용할 수 있다.