1. Spring framework란?
Spring Framework는 자바 플랫폼을 위한 오픈소스 애플리케이션 프레임워크입니다. 엔터프라이즈급 애플리케이션을 개발할 수 있는 기능을 종합적으로 제공하면서도 경량화된 솔루션을 제시합니다.
일반적인 엔터프라이즈급 개발에서는 과도한 엔지니어링 기술로 인해 고가의 WAS(Web Application Server)가 필요하지만, Spring은 필요한 기술을 가볍고 단순한 환경에서 사용할 수 있도록 제공합니다.
2. Spring framework 특징
2.1. IoC (Inversion of Control, 제어의 역전)
IoC는 객체의 생성과 관리 제어권을 개발자가 아닌 스프링 컨테이너에 넘기는 개념입니다. 전통적으로는 개발자가 직접 객체를 생성하고 의존성을 관리해야 했지만, 스프링은 이 작업을 컨테이너가 대신 처리합니다. 이로 인해 코드의 결합도가 낮아지고, 확장성과 유지보수가 훨씬 쉬워집니다.
- 등장 배경: EJB는 비즈니스 객체를 컨테이너가 관리하는 개념을 도입했지만, 무겁고 복잡한 서버 환경을 필요로 했습니다. 스프링은 POJO(Plain Old Java Object)를 기반으로, EJB가 제공하던 다양한 엔터프라이즈 기능을 가볍게 제공하기 위해 등장했습니다.
- IoC 컨테이너: 스프링의 IoC 컨테이너는 애플리케이션에서 사용되는 객체들의 라이프사이클(생성, 사용, 소멸)을 관리합니다. Bean으로 등록된 객체들만 컨테이너에서 관리되며, IoC를 통해 애플리케이션의 핵심 로직 외에 부가적인 객체 관리를 컨테이너가 맡아 처리합니다.
- 장점: 객체 간의 결합도가 낮아지며, 애플리케이션의 유지보수성과 유연성이 크게 향상됩니다. 예를 들어, IoC 컨테이너는 객체의 생성 및 주입 과정을 중앙에서 관리하므로 개발자가 이를 신경 쓰지 않고 비즈니스 로직에만 집중할 수 있습니다.
2.2. DI (Dependency Injection, 의존성 주입)
DI는 스프링 컨테이너가 객체의 의존성을 외부에서 주입해주는 방식입니다. 객체는 직접적으로 의존성을 관리하지 않고, 스프링이 알아서 의존성을 주입해줍니다. 이것은 객체 간의 결합도를 낮추고, 코드의 재사용성을 높이는 핵심 개념입니다.
- DI 구현 방법: DI는 주로 필드 주입, 생성자 주입, setter 주입의 방식으로 구현됩니다. 예를 들어,
@Autowired
어노테이션을 사용하면 컨테이너가 해당 필드나 메서드에 맞는 객체를 자동으로 주입해줍니다. - 장점: DI는 객체 간의 의존성을 명시적으로 처리하여 모듈 간 결합도를 낮추고, 더 유연하고 테스트 가능한 구조를 만듭니다. 개발자는 각 객체를 직접 생성하거나 의존성을 처리할 필요 없이, 필요한 객체를 스프링이 적절한 시점에 제공해줍니다.
2.3. AOP (Aspect Oriented Programming, 관점 지향 프로그래밍)
AOP는 횡단 관심사를 분리하여 비즈니스 로직과 분리된 형태로 관리하는 기법입니다. 예를 들어, 로깅, 트랜잭션 관리, 보안 등의 기능은 여러 비즈니스 로직에서 공통적으로 사용되는 기능이지만, 이를 개별적으로 각 로직에 구현하면 중복이 발생하게 됩니다.
- 핵심 개념: AOP는 핵심 관심사(비즈니스 로직)와 횡단 관심사(로깅, 보안 등)를 분리하여 코드 중복을 줄이고 유지보수를 쉽게 합니다. 이를 위해 AOP는 *
@Aspect
와 같은 어노테이션을 사용하여 공통적인 기능을 정의하고, 비즈니스 로직에 자동으로 적용되게 만듭니다. - 장점: 중복 코드를 줄이고, 핵심 비즈니스 로직에만 집중할 수 있게 합니다. 개발자는 핵심 로직에만 집중하고, 공통적인 기능은 AOP를 통해 모듈화하여 관리할 수 있습니다.
2.4. PSA (Portable Service Abstraction, 이식 가능한 서비스 추상화)
PSA는 다양한 기술 스택에 대해 일관된 API를 제공하여 개발자의 복잡성을 줄여주는 개념입니다. 예를 들어, 데이터베이스를 변경하더라도 동일한 API를 사용해 데이터를 처리할 수 있어, 개발 환경의 변화에 쉽게 대응할 수 있습니다.
- 데이터베이스 추상화: 스프링은 JDBC, JPA 등 다양한 데이터베이스 접근 기술을 PSA로 추상화하여, 특정 기술에 종속되지 않고도 일관된 방식으로 데이터베이스와 상호작용할 수 있게 합니다. 이를 통해 개발자는 데이터베이스의 구체적인 구현에 신경 쓰지 않고, 애플리케이션 로직에만 집중할 수 있습니다.
- 장점: PSA는 애플리케이션이 특정 기술에 의존하지 않고 다양한 환경에서 쉽게 이식될 수 있게 합니다. 예를 들어, 데이터베이스나 메시징 시스템이 바뀌더라도 애플리케이션 코드는 거의 수정하지 않고도 대응할 수 있습니다.
2.5. POJO (Plain Old Java Object, 순수 자바 객체)
POJO는 특정 프레임워크에 종속되지 않은 단순하고 가벼운 자바 객체를 의미합니다. 스프링은 POJO 기반으로 애플리케이션을 구성하여, 개발자가 복잡한 규칙에 얽매이지 않고 자유롭게 개발할 수 있도록 합니다.
- POJO의 장점: POJO는 종속성이 없기 때문에, 다른 프레임워크로의 전환이나 코드 재사용이 쉬워집니다. 또한, 개발자는 스프링에 구애받지 않고 순수 자바 코드만으로 비즈니스 로직을 구현할 수 있기 때문에 생산성과 유지보수성이 향상됩니다.
3. MVC 디자인 패턴
MVC는 Model, View, Controller로 나뉘어 사용자 요청을 처리하고 화면을 반환하는 패턴입니다.
3.1. Model
- 애플리케이션의 정보와 데이터 처리, 비즈니스 로직을 담당합니다.
- 데이터베이스와 상호작용하며, 요청에 필요한 데이터를 제공합니다.
3.2. View
- 클라이언트에 보여지는 화면을 생성하고 데이터를 사용자에게 반환하는 역할을 합니다.
- 모델에서 제공하는 데이터를 표시하는 데 집중하며, 재사용 가능하게 설계됩니다.
3.3. Controller
- 사용자의 요청을 받아 처리하고, 그 결과를 Model에 전달하여 적절한 View를 반환하는 중개 역할을 합니다.
4. Spring MVC 동작 구조
Spring MVC는 클라이언트의 요청을 수신하고 처리 결과를 반환하기 위한 흐름을 체계적으로 구성합니다. 아래는 주요 구성 요소와 동작 과정을 설명합니다.
4.1 DispatcherServlet
- 역할: Spring MVC의 핵심으로, Front Controller 패턴을 구현한 클래스입니다. 클라이언트로부터 모든 HTTP 요청을 수신하여, 알맞은 컴포넌트로 전달하고 최종 응답을 생성하는 역할을 합니다.
- 작동 방식
- 요청을 받으면 HandlerMapping을 통해 어떤 컨트롤러가 요청을 처리해야 하는지 결정합니다.
- 요청을 적절한 HandlerAdapter로 전달하여 컨트롤러의 메서드를 호출하고, 처리 결과를 ModelAndView 객체로 반환받습니다.
- 반환된 ModelAndView를 기반으로 ViewResolver를 통해 View를 결정하고, 최종 결과를 클라이언트로 반환합니다.
4.2 HandlerMapping
- 역할: DispatcherServlet이 요청을 처리할 컨트롤러(Handler)를 결정하는 컴포넌트입니다.
- 작동 방식
- 요청 URL 및 HTTP 메서드(GET, POST 등)를 기반으로 매핑된 컨트롤러를 찾아 반환합니다.
- Spring Boot에서는 기본적으로
RequestMappingHandlerMapping
이 사용됩니다.
- 특징: URL 패턴과 컨트롤러 간의 매핑 규칙을 설정하여 요청에 적합한 컨트롤러를 빠르게 찾을 수 있습니다.
4.3 HandlerAdapter
- 역할: HandlerMapping이 반환한 컨트롤러를 호출하는 중간 역할을 수행합니다. 즉, 컨트롤러를 실행하기 위한 어댑터 역할을 합니다.
- 작동 방식
- HandlerAdapter는 각기 다른 유형의 컨트롤러(@Controller, @RestController, @RequestMapping 등)를 실행할 수 있도록 일관된 방식으로 호출합니다.
- 실행된 컨트롤러 메서드는 결과를 ModelAndView 객체로 반환합니다.
- 특징: 스프링이 다양한 종류의 컨트롤러를 유연하게 지원하도록 하는 중요한 컴포넌트입니다.
4.4 Controller
- 역할: 클라이언트 요청을 처리하고 필요한 데이터를 생성하거나 처리 결과를 반환하는 비즈니스 로직의 핵심입니다.
- 작동 방식
- 요청에 포함된 데이터를 바탕으로 비즈니스 로직을 실행합니다.
- 필요한 경우 서비스 계층을 호출하고, 처리 결과를 ModelAndView 객체에 담아 DispatcherServlet에 반환합니다.
- 특징: 요청 매핑(@RequestMapping, @GetMapping 등) 어노테이션을 사용하여 HTTP 요청과 컨트롤러 메서드를 연결합니다.
4.5 ModelAndView
- 역할: 컨트롤러가 반환한 처리 결과와 클라이언트에게 보여줄 View 정보를 담는 객체입니다.
- 구성 요소
- Model: 클라이언트에게 전달할 데이터(키-값 형태)
- View: 데이터를 렌더링할 화면(View 이름)
- 특징: 데이터를 화면에 표시하기 위해 Model과 View를 함께 묶어 관리합니다.
4.6 ViewResolver
- 역할: ModelAndView 객체에 포함된 View 이름을 바탕으로 실제 렌더링할 View 파일(JSP, Thymeleaf 등)을 결정합니다.
- 작동 방식
- ViewResolver는 View 이름에 맞는 파일 경로를 매핑하고, 클라이언트에 반환할 결과 화면을 생성합니다.
- 예: View 이름이 "home"이라면
/WEB-INF/views/home.jsp
와 같은 경로로 변환
- 특징: 다양한 템플릿 엔진을 지원하며, 개발자가 View 구현 방식에 구애받지 않고 일관된 API를 사용할 수 있도록 합니다.
4.7 View
- 역할: 최종 결과를 클라이언트에게 렌더링하는 부분입니다.
- 작동 방식
- ViewResolver가 결정한 View 파일(JSP, Thymeleaf 등)을 기반으로 데이터를 렌더링하여 HTML, JSON, XML 등으로 출력합니다.
- 특징: 클라이언트의 요구에 맞는 다양한 결과 화면을 제공하며, 데이터 표현에 집중합니다.
4.8 동작 흐름 요약
- 클라이언트 요청: HTTP 요청이 DispatcherServlet으로 전달됩니다.
- HandlerMapping: 요청 URL에 맞는 컨트롤러를 결정합니다.
- HandlerAdapter: 컨트롤러를 호출하여 요청을 처리합니다.
- Controller: 요청을 처리하고 결과를 ModelAndView 객체에 담아 반환합니다.
- ViewResolver: ModelAndView의 View 이름을 해석하여 클라이언트에 반환할 최종 View를 결정합니다.
- View: 결과 데이터를 렌더링하여 클라이언트에게 응답을 반환합니다.
5. Spring MVC 패턴에서 REST API 용도로 사용할 경우 동작 흐름
Spring에서 REST API 용도로만 사용하는 서버 구조에 대해 설명할 때, 기본적인 Spring MVC 패턴과 동일한 DispatcherServlet, Controller, HandlerMapping 등의 역할은 유지됩니다. 그러나 ViewResolver와 View 부분이 사라지고, 대신 HTTP 응답이 바로 클라이언트로 전달되는 차이가 있습니다. REST API 서버에서는 주로 JSON, XML 같은 데이터 형식으로 응답하기 때문입니다.
5.1 REST API 용도의 Spring 백엔드 서버 동작 흐름
1) 클라이언트 요청 (Client Request)
클라이언트(프론트엔드 또는 다른 서버)가 HTTP 요청을 보냅니다. 이 요청은 일반적으로 GET, POST, PUT, DELETE 같은 HTTP 메서드를 사용합니다.
2) DispatcherServlet
모든 요청은 여전히 DispatcherServlet이 수신합니다. DispatcherServlet은 요청을 적절한 Controller로 전달하는 역할을 합니다.
3) HandlerMapping
HandlerMapping은 요청 URL과 HTTP 메서드를 기반으로 어떤 Controller가 해당 요청을 처리할지를 결정합니다. 이 과정에서 요청에 맞는 컨트롤러를 찾아 반환합니다.
4) Controller
RestController 또는 Controller가 클라이언트의 요청을 처리합니다. REST API에서는 주로 @RestController
어노테이션을 사용합니다. 이는 View를 반환하지 않고, JSON이나 XML과 같은 데이터를 직접 반환하는 것이 특징입니다.
- 요청 데이터가 있으면 이를 처리한 후 데이터베이스와 상호작용하고, 응답 데이터를 생성합니다.
- 일반적으로 Service나 Repository 계층을 사용하여 비즈니스 로직을 처리하고, 그 결과를 반환합니다.
5) DispatcherServlet
Controller가 처리 결과를 DispatcherServlet에 반환합니다. 여기서 반환된 결과는 ResponseEntity
나 JSON 형식의 데이터가 됩니다. View 단계가 생략되므로 더 간단합니다.
6) 응답 데이터 생성 (Response)
ViewResolver와 같은 별도의 뷰를 렌더링할 필요 없이, Controller에서 반환한 데이터가 DispatcherServlet에 의해 바로 HTTP 응답으로 클라이언트에 전달됩니다. 이 응답은 보통 JSON 형식으로 클라이언트에게 전달됩니다.
5.2 RestController와 Spring MVC의 차이
1) @RestController
Spring MVC에서 View를 반환하는 일반적인 @Controller와 달리, @RestController는 주로 API용으로 사용됩니다. 즉, View를 렌더링하지 않고 데이터만 반환합니다. @RestController는 @Controller와 @ResponseBody를 결합한 것과 같은 역할을 합니다.
2) View 처리 제거
일반적인 Spring MVC 패턴에서는 최종적으로 View(JSP, Thymeleaf 등)를 통해 HTML을 클라이언트에게 반환하지만, REST API에서는 View가 없고 데이터(JSON, XML)를 직접 반환합니다. 즉, ViewResolver는 더 이상 사용되지 않습니다.
3) 예시
- DispatcherServlet은 클라이언트의 모든 요청을 받아, HandlerMapping을 통해 적절한 Controller를 찾아 요청을 처리합니다.
- RestController는 요청에 맞는 데이터를 처리하고, 데이터베이스 작업이나 서비스 로직을 수행한 후, 최종 데이터를 JSON 형식으로 반환합니다.
- 이 데이터를 클라이언트는 받아 화면에 렌더링하거나, 추가적인 처리 작업을 할 수 있습니다.
따라서, API 용도로만 사용되는 서버에서는 뷰 처리 없이 데이터를 직접 반환하는 구조가 핵심입니다. Spring MVC 패턴의 기본적인 흐름은 유지되지만, View 처리와 관련된 부분들이 생략되고, 대신 RestController가 JSON 형태로 데이터를 반환하는 방식으로 바뀌는 차이점이 있습니다.
'BackEnd > Spring & JPA' 카테고리의 다른 글
[Spring] @RequestPart를 활용하여 JSON + MultipartFile 동시 전송하기 (Feat. 게시판에서 게시물 생성과 첨부 파일 업로드 한번에 처리하기) (0) | 2025.02.13 |
---|---|
[Spring Data JPA] JPA 엔티티 설계 시 생성자 접근 제한을 PROTECTED로 설정하는 이유 (0) | 2025.01.21 |
[Spring] @ResponseBody VS ResponseEntity<T> (0) | 2025.01.06 |
[Spring] @Controller VS @RestController (0) | 2025.01.06 |