들어가며
Spring 어플리케이션 서버에서 HTTP 요청을 어떻게 처리하는지 흐름을 알고 계신가요?
이 글은 전체적인 작동 구조에 대해 공부하여 작성해보았습니다.
요청 처리 과정
1) 요청이 웹 어플리케이션 서버에 도착 (Tomcat)
클라이언트(브라우저, 모바일 앱 등)가 HTTP 요청을 보낼 때, Spring Boot 애플리케이션이 실행 중이라면 Tomcat 내장 웹 어플리케이션 서버가 요청을 받아줍니다.
📝 요청 예제
GET /api/user/1 HTTP/1.1
Host: example.com
Authorization: Bearer some_token
✏️ 웹 어플리케이션 서버의 역할
- 요청을 받을 준비 (포트 8080 등)
- Servlet Container에게 요청 전달
2) FilterChain이 요청을 가로챔 (Spring Security 포함)
Spring Boot는 요청을 처리하기 전에 여러 개의 필터(Filter)를 실행합니다.이를 FilterChain이라고 합니다.
흔히, Spring Security를 이용해서 JwtAuthFilter를 만들어 securityFilterChain에 등록하기도 합니다.
이게 바로 FilterChain의 한 종류인 FilterProxy입니다.
📝 필터 예시
필터명 | 역할 |
SecurityContextPersistenceFilter | 인증 정보 유지 |
UsernamePasswordAuthenticationFilter | 로그인 인증 처리 |
BasicAuthenticationFilter | Basic Auth 처리 |
CsrfFilter | CSRF 보호 |
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable()) // CSRF 비활성화
.cors(withDefaults())
.authorizeHttpRequests(authorize -> authorize
.anyRequest().permitAll() // 모든 요청에 대해 인증 해제
);
http.addFilterBefore(new JwtAuthenticationFilter(jwtProvider, userDetailsService), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
✏️ FilterChain의 역할
- 보안 검사 (인증 & 인가)
- CORS 정책 적용
- CSRF 공격 방지
3) DispatcherServlet이 요청을 관리
Spring MVC의 핵심인 DispatcherServlet이 요청을 받아서 적절한 컨트롤러로 전달합니다.
✏️ DispatcherServlet의 역할
- HandlerMapping을 통해 어떤 컨트롤러가 처리할지 결정
- 요청을 HandlerAdapter를 통해 실행
- 응답을 ViewResolver를 통해 JSON, HTML, XML로 변환
4) HandlerMapping을 통해 컨트롤러 찾기
Spring은 요청에 맞는 Controller를 찾기 위해 HandlerMapping을 사용합니다.
📊 HandlerMapping 종류
- RequestMappingHandlerMapping → @RequestMapping을 기반으로 매핑
- SimpleUrlHandlerMapping → 정적 리소스 처리
@RestController
@RequestMapping("/api/club")
@AllArgsConstructor
public class ClubController {
}
컨트롤러를 만들 때 붙였던 @RequestMapping가 결국은 DispatcherServlet이 Controller를 Mapping 하기 위해서 사용했던 것 입니다.
5) Interceptor (전처리기) 실행
Spring은 컨트롤러 실행 전에 HandlerInterceptor를 실행할 수 있습니다.
✏️ Interceptor의 역할
- API 요청 로깅
- 인증/인가 검증
- 데이터 가공
public class CustomInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
System.out.println("Request URL: " + request.getRequestURI());
return true; // 요청을 계속 진행
}
}
권한, 인증과 같은 로직이나 로그를 출력하는 용도로 사용할 수도 있습니다.
메서드 | 역할 |
preHandle() | 컨트롤러 실행 전에 수행 |
postHandle( ) | 컨트롤러 수행 후 결과를 뷰로 보내기 전에 수행 |
afterCompletion() | 뷰의 작업까지 완료된 후 수행 |
상황에 따라 intercept 할 수 있어서 유용합니다.
6) Controller에서 요청 처리
HandlerAdapter가 적절한 컨트롤러의 메서드를 호출하여 요청을 처리합니다.
✏️ 컨트롤러의 역할
- 비즈니스 로직 호출
- 응답 생성 (JSON, HTML 등)
드디어 컨트롤러단에 요청이 도착했습니다.
여기서부턴 개발자가 작성한 비즈니스 로직을 수행합니다.
(Service, Repository 등의 코드 로직 수행)
응답 처리 과정
1) Controller에서 응답 반환
컨트롤러에서 클라이언트에게 보낼 응답 데이터를 생성하고 반환합니다.
@RestController
@RequestMapping("/api/user")
public class UserController {
@GetMapping("/{id}")
public ResponseEntity<UserDTO> getUser(@PathVariable Long id) {
UserDTO user = userService.getUserById(id);
return ResponseEntity.ok(user); // 200 OK 응답 반환
}
}
ResponseEntity.ok(user)를 반환하면 Spring이 자동으로 JSON 변환 후 HTTP 응답을 생성합니다.
2) Interceptor (후처리기) 실행
HandlerInterceptor의 postHandle() 또는 afterCompletion() 메서드가 실행됩니다.
public class ResponseInterceptor implements HandlerInterceptor {
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
System.out.println("응답 상태 코드: " + response.getStatus());
}
}
응답 데이터를 수정하거나, 로그를 기록할 수 있습니다.
3) DispatcherServlet이 응답 처리
컨트롤러에서 받은 응답을 적절한 형식(JSON, View 등)으로 변환합니다.
✏️ JSON 변환 과정 (RestController)
- @ResponseBody가 있으면 HttpMessageConverter가 JSON으로 변환
- 기본적으로 Jackson(MappingJackson2HttpMessageConverter) 사용
✏️ View 변환 과정 (Controller)
- @Controller 사용 시, ViewResolver가 JSP, Thymeleaf 템플릿을 렌더링
@Controller
public class PageController {
@GetMapping("/home")
public String home() {
return "home"; // home.html 템플릿 반환
}
}
4) FilterChain이 응답을 가로채서 필터 처리
SpringSecurity 필터가 응답을 검사할 수 있습니다. 예를 들어
- 인증/인가 실패 시 응답을 변경 (403 Forbidden 반환)
- 응답 헤더 수정 (CORS, X-Frame-Options 설정)
📝 필터 예시
필터 | 역할 |
ExceptionTranslationFilter | 인증 예외 처리 |
HeaderWriterFilter | 보안 헤더 추가 (CORS, CSP 등 |
LogoutFilter | 로그아웃 요청 처리 |
5) Web Server (Tomcat)이 최종 응답 반환
Spring Boot의 내장 Tomcat이 최종적으로 HTTP 응답을 클라이언트에게 전송합니다.
📝 HTTP 응답 예제
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": 1,
"name": "John Doe"
}
6) 클라이언트가 응답을 받음
브라우저, 모바일 앱, Postman 등의 클라이언트가 응답을 받아 UI에 표시합니다.
'Spring' 카테고리의 다른 글
[Spring+MongoDB]한 컬렉션에서 중복된 필드값 검증하기(feat. 고유 인덱스) (0) | 2025.02.13 |
---|---|
[Spring+MongoDB]엔티티의 기본값이 DB에 저장되지 않은 문제 (0) | 2025.02.13 |
[Spring 공식문서 정리하기] Resource 관리 (0) | 2025.01.06 |
[Spring 공식문서 정리하기] Spring IoC Container와 Beans(Feat. 의존성 주입(DI)) (1) | 2024.12.25 |