[Spring Boot] Spring Boot, MVC 패턴, IoC

임원재·2024년 7월 7일
0

SpringBoot

목록 보기
3/18
post-thumbnail

Spring Boot

  • Spring Framework에 기반한 자바 애플리케이션 프레임워크이다.
  • 웹 애플리케이션을 구성하기 위한 복잡한 과정과 설정, 기능들을 자동으로 제공하여 빠르고 편리한 개발을 가능하게 해준다.

Gradle

  • 소프트웨어를 빌드하고 관리하는 도구이다. (컴파일, 테스트, 패키징 포함)
  • 프로젝트에서 사용하는 외부 라이브러리(의존성)를 쉽게 관리한다. (build.gradle)

Tomcat

  • Tomcat(톰캣)이라는 서버(Web Application Server)를 통해 애플리케이션을 실행한다.
  • Tomcat은 동적인 데이터를 처리하는 WAS이다. 정적인 데이터를 처리하는 서버는 WS(Web Server)이다. Tomcat도 정적인 데이터를 처리 가능하나, WS의 정적 데이터 처리 성능보다 떨어진다.
  • Tomcat은 HTTP요청을 수신, 응답을 송신하는 역할을 한다.
  • HTTP요청을 Servlet(서블릿)으로 전달한다.
  • Tomcat 서버를 사용해 애플리케이션을 실행하면, 웹 애플리케이션의 역할인 HTTP요청이 처리된다.
  • Spring Framework는 Tomcat 서버를 별도로 설치해줘야하는 불편함이 있다.
  • Spring Boot는 Tomcat이 내장되어있기 때문에, 애플리케이션 실행을 통해 Tomcat을 자동으로 사용가능하다.

Servlet

  • 자바 기반의 웹 애플리케이션에서 실행되는 컴포넌트이다.
  • HTTP요청을 처리하고 이에 대응되는 응답을 생성한다.
  • Spring Boot는 Tomcat에서 수신한 모든 HTTP요청을 DispatcherServlet이라고 불리는 서블릿으로 전달한다.
  • DispatcherServlet에서 HandlerMapping을 호출한다. HTTP요청의 URL과 매칭되는 Controller(Handler)를 선택한다.
  • 매칭된 Controller(Handler)를 실행하기 위해 DispatcherServletHandlerAdapter를 호출한다. 즉, Controller의 호출을 HandlerAdapter에게 맡기는 것이다. 다양한 형태의 Controller를 지원해야 하므로 유연성과 확장성을 제공하기 위해 DispatcherServlet이 직접 Controller를 호출하지 않고 다양한 방식을 추상화하고 통합하는 HandlerAdapter에게 Controller를 호출하는 역할을 위임한다.
  • View를 리턴할 목적이라면 호출한 Controller에서 View의 이름을 리턴한다. DispatcherServlet은 이 View이름을 가지고 ViewResolver를 호출하여 실제 View를 찾아 렌더링한다. View가 아닌 JSON형태의 데이터를 반환해야하는 상황일 수도 있다. 이 경우에는 Controller는 View의 이름을 리턴하는 것이 아닌 HTTP Body에 JSON 데이터를 담아 리턴한다. DispatcherServlet은 View이름이 아니므로 ViewResolver를 호출하지 않고 그대로 반환한다.

MVC 패턴

  • Spring Boot는 MVC패턴을 사용하여 웹 애플리케이션을 개발한다.
  • MVC패턴은 Model + View + Controller로 이루어져 있다.
  • 각각의 역할을 나눠 객체지향의 특징을 반영한다.

Model

  • View에서 사용될 데이터를 담는 객체이다.
  • Controller에서 Model에 데이터, 혹은 로직을 담는다.

View

  • 사용자에게 표시되는 화면을 의미한다.
  • HTML템플릿의 형식을 사용하며, JAVA언어로 이를 표현하기 위해 JSP, Thymeleaf등을 사용하여 구현한다.
  • Model에서 데이터를 가져와 동적으로 페이지를 표현한다.

Controller

  • HTTP요청을 받아 사용자 정의 로직을 실행한다.
  • @Controller, 혹은 @RestController로 Controller임을 명시한다.
  • @Controller 애노테이션으로 Controller를 지정한 경우, 해당 Controller에 대응되는 View이름을 리턴한다. 이때 Controller에서는 해당 View에 사용될 데이터 혹은 로직을 Model에 담는다.
  • @RestController 애노테이션으로 Controller를 지정한 경우, 해당 Contoller는 사용자에게 표시되는 화면인 View를 리턴하지 않는다. 대신, HTTP body에 JSON형태의 객체 데이터를 담아 반환한다. @RestController@ResponseBody@Controller를 합친 애노테이션이다. 단순히 View가 아닌, JSON형태의 객체를 반환하고 싶을 때 @ResponseBody를 사용한다.

View 반환

  • 위에 정리한 내용을 바탕으로, Spring Boot를 실행시켜 HTTP요청을 전송하였을 때의 흐름을 이해한만큼 정리해보았다.
  • 아래 그림에서 큰 흐름은 localhost:8080에 접속하여 index.html을 받는것이다. html은 정적 파일이지만 안에 들어가있는 데이터는 계속 변하는 동적 성질을 가진다고 가정하자. View를 반환하므로 Controller에서는 @Controller애노테이션이 사용된다.

  • localhost에서 실행시킨 Spring Boot 웹 애플리케이션은 내장된 tomcat 서버가 8080포트에서 열리므로 localhost:8080 으로 시작되는 링크로 HTTP요청을 전송한다.
  • Tomcat은 해당 요청을 먼저 DispatcherServlet으로 전달한다.
  • 요청받은 url에 맞는 Controller를 찾기 위해 HandlerMapping을 호출하여 실행해야할 Controller를 Mapping하여 DispatcherServlet으로 돌아간다.
  • Mapping한 Controller를 실행하기 위해 DispatcherServletHandlerAdapter을 호출하여 Controller를 실행한다.
  • Controller는 개발자가 미리 구현해놓은 로직을 처리하기 위해 Service를 호출한다. 이때 Repository는 데이터베이스와 직접 상호작용하며 데이터를 조회, 삽입, 수정, 삭제하는 역할을 수행한다. Controller는 이를 바탕으로 Model을 생성한다. Model은 View에 필요한 데이터를 저장하는 객체이다. 호출할 View의 이름을 반환한다.
  • 다시 DispatcherServlet으로 돌아가 ViewResolver를 호출한다. ViewResolver는 ViewName으로 실제 View의 위치를 찾아 매핑한다.
  • DispatcherServlet은 View를 렌더링한. 이 과정에서 View는 Model을 사용해 HTML을 생성한다. 이때 JSP, Thymeleaf 등의 템플릿 엔진이 사용된다.
  • DispatcherServlet은 렌더링 완료된 View를 클라이언트에 응답으로 반환한다.

JSON 반환

  • Spring Boot로 웹 애플리케이션을 만들면 View를 사용하는, 즉 서버측에서 렌더링하는 방법말고 다른 방식도 사용된다.
  • API 통신을 구현하기 위해선 View가 아닌 HTTP Body에 JSON형식의 Java 객체를 반환할 필요가 있다.
  • localhost:8080을 요청했을 때
    {
    	"isSuccessed" : "true"
    }
    라는 간단한 JSON형식의 HTTP Body를 응답으로 받는다고 가정하자. 해당 JSON과 대응되는 자바 클래스를 Success라고 명명하겠다. 해당 내용은 db가 필요없지만 db에서 데이터를 가져와야한다고 가정하겠다. Java 객체를 반환하므로 Controller는 @RestController애노테이션을 사용한다.

  • View, Model과 관련된 컴포넌트들은 사용되지 않는다.
  • DispatcherServlet에서의 동작은 위와 동일하다.
  • Controller에서는 Service를 호출하여 로직을 수행하고 이를 통해 얻은 데이터를 가지고 Success 클래스의 인스턴스를 생성하여 반환한다.
  • 해당 인스턴스는 JSON 형식으로 변환되어 HTTP Body에 포함된다.
  • DispatcherServlet은 해당 응답을 클라이언트에 반환한다.

  • 위 두 다이어그램을 확인했을 때, Bean Container 안에 컴포넌트들이 들어있음을 확인할 수 있다. Spring Container라고 불리기도 한다. 이에 대해 바로 설명하기 보다 이를 왜 사용하게 됐는지부터 설명해보려고 한다.
@SpringBootApplication
public class PracticeApplication {

    public static void main(String[] args) {
        SpringApplication.run(PracticeApplication.class, args);
    }
}
  • 해당 main()함수는 SpringApplication.run(PracticeApplication.class, args)을 실행하여 스프링 부트를 실행한다. 해당 메서드는 애플리케이션을 실행하는데 필요한 객체를 생성한다.
    • SpringApplication을 생성하여 애플리케이션 초기 설정을 수행한다.

    • ApplicationContext을 생성하여 애플리케이션의 모든 Bean을 관리한다. 이는 조금 있다 후술할 예정이다.

      등등…

여기에는 어떠한 Controller, DispatcherServlet, 설정 클래스 등 위에서 언급했던 수많은 컴포넌트들을 생성하는 코드는 전혀 없다.

반대로 생각해보면 당연하다고 느낄 수 있다. 개발자들이 개발을 진행하며 수많은 API와 View를 생성할 것이다. 즉, 수많은 컨트롤러들을 생성하게 될 것이다.

만약 100개의 Controller를 작성했다고 가정하자. 만약 애플리케이션을 실행하면 어떤 url로 어떤 Controller를 호출할지 모르니 이 모든 Controller를 직접 하드코딩하여 생성자를 이용해 생성해야 할 것이다.

또한 100개를 생성해놓고 HTTP요청에 매핑되어 사용될 컨트롤러는 단 한개 뿐이다. 리소스적으로 낭비가 아닐 수 없다.

  • Spring에서는 IoC(Inversion of Control)라는 개념으로 위와 같은 문제를 방지한다.

Ioc(Inversion of Control)

  • IoC는, Spring에서 사용될 컴포넌트들을 애플리케이션을 실행할 때 모두 생성하는 것이 아닌, 생성의 권한을 Spring에게 일임하는 디자인 패턴을 뜻한다.
  • 개발자는 애플리케이션을 실행할 때 클래스의 생성 권한을 관리하는 ApplicationContext만 생성하면 된다.
  • 이때 Spring 컨테이너(ApplicationContext)에 의해 관리되는 객체를 Bean이라고 한다.

Bean

  • Spring Container에 의해 관리되는 자바 객체이다.
  • 개발자가 모든 클래스들을 생성할 수 없으므로 Spring에게 생성 권한을 넘길 객체이다.
  • @Configuration, @Component, @Controller, @Service, @Repository, @Bean 등 모두 메서드, 혹은 클래스를 자동으로 생성 가능하도록 빈으로 등록하는 애노테이션이다.

Spring Container

  • Bean을 관리하는 컴포넌트이다.
  • ApplicationContext가 Spring Container의 구현체이다.
  • 애플리케이션을 실행할 때 ApplicationContext를 생성하여 빈으로 등록된 클래스들을 관리한다.

이러한 기술을 통해 모든 클래스를 생성하지 않고도 웹 애플리케이션 실행이 가능해지며 리소스 관리도 더욱 효율적으로 할 수 있다.

0개의 댓글