요청을 받아, 그에 대한 처리 뒤, 응답을 반환한다.
Spring Controller의 동작 원리
Spring MVC에서 Controller는 사용자의 요청을 받아 처리한 뒤 그에 따른 응다블 반환하는 역할을 한다. 이 때 Controller는 단독으로 동작하는 것이 아니라, DispatcherServlet이라는 Front Controller를 통해 요청을 처리한다. Spring은 이 구조를 통해 클라이언트의 요청을 일관되게 관리하고 적절한 Controller로 라우팅한다.
DispatcherServlet과 요청 처리 흐름
Spring MVC에서 모든 요청은 먼저 DispatcherServlet에 의해 처리된다. DispatcherServlet은 클라이언트로부터 들어온 요청을 Controller로 전달하고, 최종 응답을 반환하는 역할을 수행한다.
저번 포스팅에서 이미 다뤘던 내용이지만 이번 포스팅에서도 필요한 내용이니까 다시 한 번 정리해보도록 하겠다. (https://1000sang-dev.tistory.com/55)
[Spring] Spring MVC 원리
데이터(Model), 화면(View), 연결해주는 ControllerSpring MVC 원리Spring MVC는 Model-View-Controller 패턴을 기반으로 하여, 웹 애플리케이션의 다양한 구성 요소가 역할을 분담하여 동작한다.이 구조는 특히
1000sang-dev.tistory.com
요청 흐름:
1. 사용자 요청이 들어오면, 요청은 DispatcherServlet에 전달된다.
2. DispatcherServlet은 요청을 처리할 Handler를 찾기 위해 HandlerMapping을 사용한다.
3. 적합한 HandlerAdapter를 찾아, Controller의 로직을 실행할 수 있도록 위임한다.
4. Controller는 비즈니스 로직을 처리한 후, 결과를 DispatcherServlet에 반환한다.
5. DispatcherServlet은 반환된 데이터를 기반으로 응답을 생성해 클라이언트에게 반환한다.
- HandlerMapping: 요청에 해당하는 처리 메서드가 존재하는지 검색해본다.
- HandlerAdapter: Spring에게 처리를 위임한다.
HandlerMapping과 HandlerAdatper
HandlerMapping은 들어온 요청에 맞는 Controller를 찾는 역할을 한다. 아래 HandlerAdaters를 모두 순회하며 적합한 HandlerAdapter를 검색한다.
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
Iterator var2 = this.handlerAdapters.iterator();
while (var2.hasNext()) {
HandlerAdapter adapter = (HandlerAdapter) var2.next();
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
위 코드는 DispatcherServlet이 HandlerAdater를 찾아주는 방식의 일부다. 요청에 맞는 Controller가 있으면, 해당 Controller가 요청을 처리할 수 있는지 HandlerAdater를 통해 확인한다.
- HttpRequestHandlrAdater
- SimpleControllerHandlerAdapter
- RequestMappingHandlerAdapter
- HandlerFunctionAdapter
일반적으로는 HandlerMapping에 의해 RequestMappingHandlerAdater가 선택되어 실행한다.
Controller 동작 과정
일반적으로 Controller @Controller 어노테이션으로 선언되며, @RequestMapping이나 @GetMapping, @PostMapping과 같은 어노테이션을 사용해 특정 요청을 처리할 메서드를 정의한다.
@Controller
public class SampleControler {
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String sayHello() {
retrun "hello"; // ViewTemplate "hello.html"을 반환
}
}
이 메서드는 "/hello" 라는 URL 요청이 들어왔을 때, hello라는 ViewTemplate을 반환한다.
DispatcherServlet은 이 반환값을 ViewResolver로 전달하여, 적절한 HTML 파일을 찾아 렌더링 한 후 사용자에게 반환한다.
new로 객체를 안만드는 이유
Spring에서는 개발자가 직접 new로 객체를 생성하지 않고도, Controller나 Service 같은 클래스가 자동으로 생성되고 주입된다.
이것은 Spring의 Bean 관리 덕분이다. Spring은 애플리케이션의 주요 객체를 Bean으로 관리하며, 기본적으로 싱글톤(Singleton) 패턴을 사용하여 한 번만 객체를 생성하고 재사용한다.
@Controller
public class UserController {
@Autowired
private UserService userService; // 직접 new하지 않고 자동으로 주입됨.
@RequestMapping("/user")
public String getUser() {
return userService.getUser();
}
}
위 코드에서 UserService가 new로 생성되지 않았음에도, Spring이 자동으로 UserService 객체를 생성하고 UserController에 주입해준다. 이를 의존성 주입(Dependency Injdection)이라고 하며, Spring은 ApplicationContext라는 컨테이너를 통해 이러한 객체들의 생명 주기를 관리한다.
- Spring Bean은 2가지만 기억하자
- Bean 등록: Spring Container 내 싱글톤 객체로 등록
- Bean 사용: Spring Container에 등록되어 있는 싱글톤 객체를 가져와 주입하여 사용
- Spring Container는 ApplicationContext라 불리기도하고 이는 2개로 분리된다.
- Servlet WebApplicationContext: @Controller 등
- Root WebApplicationContext: @Servce, @Repository
Bean 등록 방법: Spring Container 내 싱글톤 객체로 등록
- @ComponentScan + @Component를 통한 등록(Package 지정 가능)
- @Controller, @Service, @Repository 등을 통한 등록
- @Configuration + @Bean
Bean 사용 방법: Spring Container에 등록되어있는 싱글톤 객체를 가져와 주입하여 사용
- 구체 클래스를 지정하여 Bean 객체 사용 ← 구체 클래스로 Bean등록
- 부모 클래스를 지정하여 Bean 객체 사용 ← 부모 클래스의 자식 클래스로 Bean 등록
- 인터페이스를 지정하여 Bean 객체 사용 ← 인터페이스의 구체 클래스로 Bean 등록
- 다수 자식 클래스 혹은 다수 인터페이스의 구체 클래스를 Collection 자료 구조로 Bean 사용
ℹ️참고
[ASAC 6기 강의자료]
'💻DEV-STUDY > Spring' 카테고리의 다른 글
Spring Bean 원리과 의존성 주입 (1) | 2024.10.06 |
---|---|
[Spring]HttpMessageConverter (0) | 2024.10.06 |
[Spring] Controller 처리 반환 (1) | 2024.10.05 |
[Spring] Spring MVC 원리 (0) | 2024.10.04 |
[Spring] 페이지 반환 (0) | 2024.10.04 |