레이어드 아키텍처(Layered Archiecture)
레이어드 아키텍처는 애플리케이션의 컴포넌트를 유사 관심사를 기준으로 레이어(계층)로 묶어 수평적으로 구성한 구조를 말한다.
일반적으로 프레젠테이션 계층, 비즈니스 계층, 데이터 접근 계층의 3계층으로 구성된다.
(4 계층이라고 표현할 경우, 인프라 계층(데이터베이스)까지 포함한 것이다.)
우리가 일반적으로 Spring을 배우고, 사용하다 보면 자연스럽게 Controller - Service - Repository의 순서로 데이터베이스에 접근하고, 역순으로 응답을 전달하게 된다. 여기서 각각 Controller가 프레젠테이션 계층, Service가 비즈니스 계층, Repository가 데이터 접근 계층이라고 보면 된다.
프레젠테이션 계층(Presentation Layer)
- 애플리케이션의 최상단 계층
- 클라이언트의 요청을 해석하고 응답
- UI 또는 API를 제공한다.
- 비즈니스 로직은 포함하지 않고, 비즈니스 계층으로 요청을 위임하여 반환받은 결과를 응답하는 역할만 수행한다.
비즈니스 계층(Business Layer)
- 애플리케이션이 제공하는 기능을 정의하고, 세부 작업을 수행한다.
- 스프링에서는 서비스 계층(Service Layer)이라고 부르기도 한다.
데이터 접근 계층(Data Access Layer)
- 데이터베이스에 직접 접근하는 모든 작업을 수행한다.
스프링에서의 레이어드 아키텍처
스프링 부트에서 일반적으로 spring-boot-starter-web 의존성을 사용할 때는 Spring MVC 구조를 갖고, 아래와 같은 레이어드 아키텍처를 이루게 된다.
Spring MVC는 Model - View - Controller 구조로, View와 Controller는 프레젠테이션 계층 영역이고,
Model은 비즈니스 계층과 데이터 접근 계층의 영역으로 구분할 수 있다.
DispatcherServlet이 프레젠테이션 계층을 담당한다. (직접적으로는 Controller을 통해 다른 계층과 통신한다.)
비즈니스 계층에는 서비스를 배치하여 엔티티와 같은 도메인 객체와 함께 비즈니스 로직을 처리하고,
데이터 접근 계층에는 DAO(Data Access Object)를 배치하여 도메인을 관리한다.
Spring에서 대부분 사용하는 Spring Data JPA에서는 Repository가 DAO의 역할을 한다.
레이어드 아키텍처 Example
Entity
예제에서 사용할 Entity 클래스이다.
@Getter@Setter
@AllArgsConstructor
@Entity
public class MyUser {
@Id
private String userId;
private String password;
}
Controller
@RestController
public class MyController {
@Autowired
private MyService myService;
@GetMapping("/user/{userId}")
public ResponseEntity<?> userInfo(@PathVariable String userId){
MyUser user = myService.getUser(userId);
return ResponseEntity.ok(user);
}
}
컨트롤러에서는 클라이언트에서 요청을 받는다.
위의 예제에서는 /user/{userId}의 URI로 요청을 받는다.
가까운 하위 레이어인 비즈니스 계층의 MyService의 의존성을 주입받은 상태이고,
요청을 받으면 myService로 파라미터 userId만 전달한다.
Service
@Service
public class MyService{
@Autowired
private MyRepository myRepository;
public MyUser getUser(String userId) {
return myRepository.findById(userId);
}
}
서비스 계층에서는 상위 계층(Controller)로부터 받은 userId 정보를 이용하여 비즈니스 로직을 처리한다.
서비스 계층에서도 마찬가지로 가까운 하위 레이어인 데이터 접근 계층의 MyRepository의 의존성을 주입받은 상태이다.
Controller로부터 받은 userId를 처리하여 MyRepository로 파라미터를 전달하여 원하는 데이터를 받는다.
Repository
@Repository
public interface MyRepository extends JpaRepository<MyUser, String>{
}
데이터 접근 계층인 repository에서는 데이터베이스에 직접 접근하여 데이터베이스로부터 데이터를 받아와서,
상위 계층인 서비스계층으로 반환한다.
정리
클라이언트 요청 -> Controller -> Service -> Repository -> Service -> Controller -> 클라이언트 응답
위와 같이 상위 계층은 가장 가까운 하위 계층의 의존성을 주입받고 하위계층으로 요청을 전달한다.
하위 계층은 요청을 처리하여 상위 계층으로 반환한다.
이렇게 계층적 설계를 하면, 여러가지 이점이 생긴다.
각 계층은 관심사에 따라 묶여있어서, 다른 계층의 역할을 침범하지 않는다. 이에 따라 각 컴포넌트의 역할이 명확해지므로 코드의 가독성과 기능 구현에 유리하고, 확장성이 좋아진다.
또한 각 계층이 독립적으로 작성되기 때문에 다른 레이어와의 의존성을 낮춰 단위테스트에 유리하다.
이 글은 '스프링 부트 핵심 가이드' 책을 참고하여 썼습니다.
'컴퓨터 공학 > 프로그래밍 이론' 카테고리의 다른 글
[Spring / 스프링 부트 핵심 가이드] 디자인 패턴 정리 (0) | 2023.10.01 |
---|---|
[ComputerScience / 디자인 패턴] 브릿지 패턴(Bridge Pattern, 가교 패턴) (0) | 2023.10.01 |
[Spring / 스프링 부트 핵심 가이드] 제어의 역전(IoC, DI, AOP) (0) | 2023.09.30 |
[ComputerScience / 디자인 패턴]싱글톤 패턴(singleton pattern) (0) | 2023.04.20 |
[프로그래밍 이론] 객체지향 4대 특성(캡슐화, 상속, 다형성, 추상화), 5 원칙(SOLID) (0) | 2023.04.20 |