티스토리 뷰

1) 레이어드 아키텍처(Layered Architecture) ?

  • 웹페이지 안에는 여러 개의 구성요소들이 존재합니다. 검색하는 부분도 있고, 로그인하는 부분도 있고, 내용을 보여주는 부분도 있습니다. 그런데 이런 구성요소들을 살펴보면 중복되는 요소들이 있습니다. 이런 URL 요청을 처리하는 컨트롤러를 잠깐 생각해본다면 URL은 다르지만 URL에 해당하는 웹페이지를 보여주기 위해서 실행되는 부분 중에 중복이 되는 부분이 있다면 어떻게 해야 될까요?

Controller에서 중복되는 부분을 처리하려면?

  • 별도의 객체로 분리합니다.
  • 별도의 메소드로 분리합니다.
  • 예를 들어 쇼핑몰에서 게시판에서도 회원 정보를 보여주고, 상품 목록 보기에서도 회원 정보를 보여줘야 한다면 회원 정보를 읽어오는 코드는 어떻게 해야 할까요?
    -
    잘 생각해보시면 게시판을 보여주는 컨트롤러도 별도로 있을 거고 상품의 목록을 보여주는 컨트롤러도 별도로 있겠죠. 그러니까 회원 정보를 읽어들이는 것만 별도의 객체로 만들고 해당 컨트롤러들은 이 객체를 이용하면 되겠죠?

컨트롤러와 서비스

  • 비즈니스 메서드를 별도의 Service객체에서 구현하도록 하고 컨트롤러는 Service객체를 사용하도록 합니다.
  • 컨트롤러들이 중복적으로 호출되는 부분들을 별도의 객체인 서비스로 구현을 하게 됩니다. 서비스 객체는 보통 업무와 관련된 메서드를 가지고 있으며 이것들을 비즈니스 메서드 라고 얘기를 합니다.

  • 그림을 잠깐 보면 상품 서비스의 경우에는 컨트롤러 1번도 이용하고 컨트롤러 3번도 이용합니다. 그랬을 때 컨트롤러 1이나 3에 각각 구현하는 것이 아니라 상품에 관련된 비즈니스만 처리하는 이런 서비스 객체를 따로 만들어놓고 컨트롤러 1도 사용하고 컨트롤러 3도 사용하게 하면 더 효율적일 것입니다.

서비스(Service)객체란?

  • 비즈니스 로직(Business logic)을 수행하는 메소드를 가지고 있는 객체를 서비스 객체라고 합니다.
  • 보통 하나의 비즈니스 로직은 하나의 트랜잭션으로 동작합니다.

트랜잭션(Transaction)이란?

  • 트랜잭션의 특징은 크게 4가지로 구분됩니다.
    1. 원자성 (Atomicity)
    2. 일관성 (Consistency)
    3. 독립성 (Isolation)
    4. 지속성 (Durability)

원자성 (Atomicity)

  • 전체가 성공하거나 전체가 실패하는 것을 의미합니다.
  • 예를 들어 "출금"이라는 기능의 흐름이 다음과 같다고 생각해봅시다.
    1. 잔액이 얼마인지 조회한다.
    2. 출금하려는 금액이 잔액보다 작은지 검사한다.
    3. 출금하려는 금액이 잔액보다 작다면 (잔액 - 출금액)으로 수정한다.
    4. 언제, 어디서 출금했는지 정보를 기록한다.
    5. 사용자에게 출금한다.
  • 이렇게 순차적으로 1, 2, 3, 4, 5라고 되어 있지만 이것들 하나하나를 다른 일이라고 생각할 수는 없습니다. 이것들은 그냥 1번부터 5번까지가 하나로 묶인 출금이라는 기능이지 이것들을 따로 나눠서 생각해서는 안 된다는 그런 이야기입니다. 이런 것들을 원자성이라고 합니다.
  • 만약 위의 작업이 4번에서 오류가 발생했다면 어떻게 될까요4번에서 오류가 발생했다면, 앞의 작업을 모두 원래대로 복원을 시켜야 합니다.
    이를 rollback이라고 합니다.
  • 5번까지 모두 성공했을 때만 정보를 모두 반영해야 합니다.
    이를 commit 한다고 합니다.
  • 이렇게 rollback 하거나 commit을 하게 되면 하나의 트랜잭션 처리가 완료됩니다.

일관성 (Consistency)

  • 일관성은 트랜잭션의 작업 처리 결과가 항상 일관성이 있어야 한다는 것입니다.
  • 트랜잭션이 진행되는 동안에 데이터가 변경되더라도 업데이트된 데이터로 트랜잭션이 진행되는 것이 아니라, 처음에 트랜잭션을 진행하기 위해 참조한 데이터로 진행됩니다.
  • 이렇게 함으로써 각 사용자는 일관성 있는 데이터를 볼 수 있는 것입니다.

독립성 (Isolation)

  • 독립성은 둘 이상의 트랜잭션이 동시에 병행 실행되고 있을 경우에 어느 하나의 트랜잭션이라도 다른 트랜잭션의 연산을 끼어들 수 없습니다.
  • 하나의 특정 트랜잭션이 완료될 때까지, 다른 트랜잭션이 특정 트랜잭션의 결과를 참조할 수 없습니다.
  • 예를 들면 데이터베이스를 사용하는 사용자가 여럿일 때 A라는 사용자가 입력이나 수정이나 삭제나 이런 일들을 수행하고 있었고 B라는 사용자도 이런 일들을 수행하려 하면 A가 하고 있는 작업들이 commit을 한다거나 rollback을 한다거나 이런 트랜잭션을 완료하기 전까지 B라는 사용자는 해당 부분에 대해서 알 수 없고 A가 하고 있는 작업에 관여도 안되며 다루고 있는 것을 B가 건들지도 못합니다. 이런 부분들이 독립성이다 하고 보시면 되겠습니다.

지속성 (Durability)

  • 지속성은 트랜잭션이 성공적으로 완료됐을 경우결과는 영구적으로 반영되어야 한다는 점입니다.

JDBC 프로그래밍에서 트랜잭션 처리 방법

  • DB에 연결된 후 Connection객체의 setAutoCommit메소드에 false를 파라미터로 지정합니다.
  • 입력, 수정, 삭제 SQL이 실행을 한 후 모두 성공했을 경우 Connection이 가지고 있는 commit()메소드를 호출합니다.
  • AutoCommit의 디폴트는 true로 되어있습니다. 그러면 commit 같은 명령을 수행하지 않아도 DB에 수정내용이 적용됩니다.
  • 지금처럼 여러 개의 작업이 끝나서 그 작업들이 모두 성공했야만 나는 commit을 반영하겠다고 한다면 해당 메서드에 false라고 파라미터를 지정하신 다음에 일들을 다 수행하고 조건이 만족했을 때만 commit()이라는 메서드를 수행하게끔 코드를 만들면 JDBC에서도 트랜잭션을 처리할 수 있습니다.

@EnableTransactionManagement

  • Spring Java Config파일에서 트랜잭션을 활성화 할 때 사용하는 애노테이션입니다.
  • Java Config를 사용하게 되면 PlatformTransactionManager 구현체를 모두 찾아서 그 중에 하나를 매핑해 사용합니다.
  • 특정 트랜잭션 매니저를 사용하고자 한다면 TransactionManagementConfigurer Java Config파일에서 구현하고 원하는 트랜잭션 매니저를 리턴하도록 합니다.
  • 아니면, 특정 트랜잭션 매니저 객체를 생성시 @Primary 애노테이션을 지정합니다.

서비스 객체에서 중복으로 호출되는 코드의 처리(중복으로 query하는 부분)

  • 데이터 엑세스 메소드를 별도의 Repository(Dao) 객체에서 구현하도록 하고 Service Repository객체를 사용하도록 합니다.
  • 서비스 객체들마다 비즈니스 메서드를 가지고 있고 이런 하나의 비즈니스 메서드는 트랜잭션 단위로 보통 작업이 처리가 되는데요하나의 트랜잭션에는 여러 개의 DB 작업이 수행될 수도 있습니다이때 비즈니스 메서드마다 중복되는 기능을 호출하는 경우도 있고요서비스 객체에서도 중복되는 부분은 역시 별도의 객체로 분리하거나 별도의 메서드로 분리해서 사용해야 합니다.

레이어드 아키텍처

  • Presentation Layer에서는 컨트롤러 객체가 동작합니다.
    Service Layer
    에서는 비즈니스 메서드를 가지고 있는 서비스 객체가 동작합니다.
    Repository Layer 부분은 실제 데이터베이스에 접근해서 데이터를 가져오는 일들만 수행합니다.
  • Service 객체는 해당 Repository Layer에 있는 DAO 객체를 사용합니다. 점점 개발하면서 이 로직을 Presentation Layer에 놓는 게 맞을까, Service Layer에 놓는 게 맞을까, DAO 쪽에 놓는 게 맞을지 이런 부분들을 계속 고민해야 합니다. 이런 부분들을 많이 생각하시면서 구현을 하시게 될 거예요.
  • 이런 그림에서 봤을 때 Presentation Layer는 지금 과정에서는 웹이기 때문에 Presentation Layer가 웹에서 보여지게 만들고 있습니다. Presentation Layer 부분을 다른 걸로 바꾸면 얼마든지 여기에 있는 Service DAO를 재사용해서 만들어낼 수 있습니다. 예를 들어서 자바로 Window 프로그래밍을 한다면 Service 객체와 DAO 부분을 그대로 사용하고 Presentation Layer Window 프로그래밍으로 바꿀 수도 있습니다. 재사용 측면이나 유지 보수적인 면에서 봤을 때 지금 Presentation Layer 쪽과 뒤쪽에 있는 이 부분은 아예 설정 파일들도 분리를 하는 게 좋습니다.
  • 언제든지 Presentation Layer와 이 부분을 따로 떼서 생각할 수도 있습니다. 그렇게 하기 위해서는 여기에 대한 설정과 Presentation Layer에 대한 설정을 따로따로 관리해야지 나중에 이 부분들을 떼낼 때도 편할겁니다.

설정의 분리

  • 실제 구현하실 때 설정 분리하지 않고 다 한꺼번에 해도 되는데 방금과 같은 이유 때문에 Service Layer Repository Layer에 관련된 설정과 Presentation Layer 쪽에 관련된 설정들을 나눠서 사용하는 게 좋습니다.
  • Spring 설정 파일을 프리젠테이션 레이어쪽과 나머지를 분리할 수 있습니다.
  • web.xml 파일에서 프리젠테이션 레이어에 대한 스프링 설정은 DispathcerServlet이 읽도록 하고, 그 외의 설정은 ContextLoaderListener를 통해서 읽도록 합니다.
  • DispatcherServlet을 경우에 따라서 2개 이상 설정할 수 있는데 이 경우에는 각각의 DispathcerServlet ApplicationContext가 각각 독립적이기 때문에 각각의 설정 파일에서 생성한 빈을 서로 사용할 수 없습니다.
  • 위의 경우와 같이 동시에 필요한 빈은 ContextLoaderListener를 사용함으로써 공통으로 사용하게 할 수 있습니다. DispatcherServlet 2개 이상 설정하는 것이 흔한 경우는 아니에요. 그런데 2개 이상 설정하고 빈을 공통으로 사용하고 싶다 이랬을 때는 이런 ContextLoaderListener를 사용해서 공통으로 사용하게 할 수도 있습니다.
  • ContextLoaderListener DispatcherServlet은 각각 ApplicationContext를 생성하는데, ContextLoaderListener가 생성하는 ApplicationContext root컨텍스트가 되고 DispatcherServlet이 생성한 인스턴스는 root컨텍스트를 부모로 하는 자식 컨텍스트가 됩니다.
  • 참고로, 자식 컨텍스트들은 root컨텍스트의 설정 빈을 사용할 수 있습니다.

생각해보기

  • 레이어로 구성하지 않을 경우 어떤 문제가 발생할까요?
  • 레이어를 구성하지 않고 중복코드를 제거할 수 있을까요?

참고 자료

[참고링크] Understanding Spring Web Application Architecture: The Classic Way
https://www.petrikainulainen.net/software-development/design/understanding-spring-web-application-architecture-the-classic-way/

[참고링크] Architecture - Tutorial for Telosys Tools 2.1
https://sites.google.com/site/telosystutorial/springmvc-jpa-springdatajpa/presentation/architecture

 

Comments