
build.gradle)DispatcherServlet이라고 불리는 서블릿으로 전달한다.DispatcherServlet에서 HandlerMapping을 호출한다. HTTP요청의 URL과 매칭되는 Controller(Handler)를 선택한다.DispatcherServlet은 HandlerAdapter를 호출한다. 즉, Controller의 호출을 HandlerAdapter에게 맡기는 것이다. 다양한 형태의 Controller를 지원해야 하므로 유연성과 확장성을 제공하기 위해 DispatcherServlet이 직접 Controller를 호출하지 않고 다양한 방식을 추상화하고 통합하는 HandlerAdapter에게 Controller를 호출하는 역할을 위임한다.DispatcherServlet은 이 View이름을 가지고 ViewResolver를 호출하여 실제 View를 찾아 렌더링한다. View가 아닌 JSON형태의 데이터를 반환해야하는 상황일 수도 있다. 이 경우에는 Controller는 View의 이름을 리턴하는 것이 아닌 HTTP Body에 JSON 데이터를 담아 리턴한다. DispatcherServlet은 View이름이 아니므로 ViewResolver를 호출하지 않고 그대로 반환한다.Model + View + Controller로 이루어져 있다.@Controller, 혹은 @RestController로 Controller임을 명시한다.@Controller 애노테이션으로 Controller를 지정한 경우, 해당 Controller에 대응되는 View이름을 리턴한다. 이때 Controller에서는 해당 View에 사용될 데이터 혹은 로직을 Model에 담는다.@RestController 애노테이션으로 Controller를 지정한 경우, 해당 Contoller는 사용자에게 표시되는 화면인 View를 리턴하지 않는다. 대신, HTTP body에 JSON형태의 객체 데이터를 담아 반환한다. @RestController는 @ResponseBody와 @Controller를 합친 애노테이션이다. 단순히 View가 아닌, JSON형태의 객체를 반환하고 싶을 때 @ResponseBody를 사용한다.localhost:8080에 접속하여 index.html을 받는것이다. html은 정적 파일이지만 안에 들어가있는 데이터는 계속 변하는 동적 성질을 가진다고 가정하자. View를 반환하므로 Controller에서는 @Controller애노테이션이 사용된다.
localhost:8080 으로 시작되는 링크로 HTTP요청을 전송한다.DispatcherServlet으로 전달한다.HandlerMapping을 호출하여 실행해야할 Controller를 Mapping하여 DispatcherServlet으로 돌아간다.DispatcherServlet은 HandlerAdapter을 호출하여 Controller를 실행한다.DispatcherServlet으로 돌아가 ViewResolver를 호출한다. ViewResolver는 ViewName으로 실제 View의 위치를 찾아 매핑한다.DispatcherServlet은 View를 렌더링한. 이 과정에서 View는 Model을 사용해 HTML을 생성한다. 이때 JSP, Thymeleaf 등의 템플릿 엔진이 사용된다.DispatcherServlet은 렌더링 완료된 View를 클라이언트에 응답으로 반환한다.localhost:8080을 요청했을 때{
"isSuccessed" : "true"
} 라는 간단한 JSON형식의 HTTP Body를 응답으로 받는다고 가정하자. 해당 JSON과 대응되는 자바 클래스를 Success라고 명명하겠다. 해당 내용은 db가 필요없지만 db에서 데이터를 가져와야한다고 가정하겠다. Java 객체를 반환하므로 Controller는 @RestController애노테이션을 사용한다.
DispatcherServlet에서의 동작은 위와 동일하다.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요청에 매핑되어 사용될 컨트롤러는 단 한개 뿐이다. 리소스적으로 낭비가 아닐 수 없다.
ApplicationContext만 생성하면 된다.ApplicationContext)에 의해 관리되는 객체를 Bean이라고 한다.@Configuration, @Component, @Controller, @Service, @Repository, @Bean 등 모두 메서드, 혹은 클래스를 자동으로 생성 가능하도록 빈으로 등록하는 애노테이션이다.ApplicationContext가 Spring Container의 구현체이다.ApplicationContext를 생성하여 빈으로 등록된 클래스들을 관리한다.이러한 기술을 통해 모든 클래스를 생성하지 않고도 웹 애플리케이션 실행이 가능해지며 리소스 관리도 더욱 효율적으로 할 수 있다.