지난 글에서는 SpringBoot가 다중 요청을 Tomcat의 스레드 풀로 어떻게 처리하는지를 살펴봤다.
이번에는 그 요청 흐름에 우리가 개입하거나 상태를 유지하고, 반응하는 방법에 대해 알아본다.
즉, 단순히 요청을 “받는” 것을 넘어, 요청을 다루는 구조(Scope와 Lifecycle)가 어떻게 동작하는지를 이해하는 것이 핵심이다.
지난 글에서는 SpringBoot에서 다중 요청이 들어왔을 때,
Tomcat이 어떻게 스레드 풀(Thread Pool)을 통해 요청을 처리하고,
Spring은 DispatcherServlet을 중심으로 요청을 분기 처리한다는 흐름을 다뤘다.
하지만 요청을 잘 "받는 것"만큼이나 중요한 건,
요청 흐름에 직접 개입하거나, 요청 간 상태를 유지하거나, 시스템 이벤트에 반응하는 능력이다.
이번 글에서는 그 역할을 담당하는 세 가지 핵심 구조인 Session, Filter, Listener에 대해 정리한다.
서블릿에서 제공하는 HttpSession은 사용자별로 상태를 서버에서 유지할 수 있는 가장 기본적인 구조다.
예를 들어 로그인한 사용자의 정보를 서버에 저장해두고,
이후 요청마다 해당 세션 값을 조회하여 사용자 인증 상태를 유지할 수 있다.
// 세션에 값 저장
HttpSession session = request.getSession();
session.setAttribute("username", "eunbeen");
// 이후 요청에서 세션 값 조회
String name = (String) session.getAttribute("username");
세션은 내부적으로 JSESSIONID라는 쿠키를 통해 브라우저와 연결되며,
서버는 이 ID를 기준으로 동일 사용자의 세션을 식별한다.
Spring에서는 기본적으로 HttpSession을 그대로 사용할 수 있으며,
Redis와 같은 외부 저장소를 이용한 세션 분산 처리도 지원한다.
Filter는 모든 요청을 서블릿으로 전달하기 전/후에 공통 로직을 삽입할 수 있는 기능이다.
가장 대표적인 용도는 요청 로깅, 인코딩 처리, 인증/인가 처리 등이다.
@WebFilter(urlPatterns = "/*")
public class LogFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("[Filter] 요청 시작: " + request.getRemoteAddr());
chain.doFilter(request, response); // 다음 필터 또는 서블릿 실행
System.out.println("[Filter] 요청 종료");
}
}
SpringBoot에서는 @ServletComponentScan을 통해 위 필터를 자동 인식시킬 수 있으며,
FilterRegistrationBean을 사용해 자바 설정 방식으로 등록할 수도 있다.
Listener는 서블릿 컨테이너 내부에서 발생하는 다양한 이벤트(생성/소멸 등)에 반응하는 구조다.
가장 대표적인 예는 세션의 생성/만료 이벤트를 감지하는 HttpSessionListener이다.
@WebListener
public class SessionListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("세션 생성됨: " + se.getSession().getId());
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("세션 종료됨: " + se.getSession().getId());
}
}
이 외에도 ServletContextListener, ServletRequestListener 등을 통해
어플리케이션 전체 또는 요청 단위의 생명주기를 감지할 수 있다.
| 구성요소 | 주요 목적 | 개입 시점 |
|---|---|---|
| Session | 사용자별 상태 유지 | 요청 간 |
| Filter | 요청/응답 공통 로직 삽입 | 서블릿 호출 전/후 |
| Listener | 세션, 애플리케이션 이벤트 감지 | 생성/종료 시점 |