[Spring] Servlet

DaeHoon·2023년 7월 23일
0

Servlet

  • 동적 웹 페이지를 만들 때 사용되는 자바 기반의 웹 애플리케이션 프로그래밍 기술
  • 간단히 말해서, 서블릿이란 자바를 사용하여 웹을 만들기 위해 필요한 기술
  • 웹을 만들때는 다양한 요청(Request)과 응답(Response)이 있고 각자 다른 프로토콜이 존재한다. 서블릿은 이러한 웹 요청과 응답의 흐름을 간단한 메서드 호출만으로 다룰 수 있게 해준다.

Spring Servlet Stack

1. Servlet Containers

  • Apache Tomcat, Jetty, JBoss등
  • Java Servlet을 실행하고 관리한다.

구조

  • request-per-thread 모델을 사용하여 요청이 들어올때마다 쓰레드를 할당하여 여러 클라이언트 요청을 동시에 처리
  • Connector를 통해서 HTTP 통신을 수행
  • Filter는 각 요청, 응답의 내용과 헤더를 변환한다.
  • 클라이언트의 요청을 Servlet의 service 메소드에 넘겨주고 그 결과를 응답으로 전달한다.
  • Servlet의 initdestroy 메소드로 생명주기를 담당한다.

Thread Per Request 모델이란?

  • 웹 서버에서 요청이 들어올 때마다 새로운 스레드를 생성하여 해당 요청을 처리하는 방식. 각 요청은 독립적으로 실행되기 때문에 동시에 여러 요청을 처리할 수 있다.

2. Servlet API

public interface Servlet {
    public void init(ServletConfig config)
            throws ServletException;
    public void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException;
    public void destroy();
}
  • Java EE Servlet에서 정의하였고 현재는 Jakarta EE Servlet에서 지원한다.
  • init: Servlet을 초기화할 때 사용. Servlet 객체를 생성할 때 사용되며 이후 ServletContainer에 등록
  • service: 클라이언트의 요청에 따라서 비즈니스 로직을 실행하고 응답 반환
  • destroy: Servlet 종료시 수행. 리소스 해제 등 을 맡는다

HttpServlet

public abstract class HttpServlet extends GenericServlet {
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {...}
    protected void doHead(HttpServletRequest req, HttpServletResponse resp) {...}
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) {...}
    protected void doPut(HttpServletRequest req, HttpServletResponse resp) {...}
    protected void doDelete(HttpServletRequest req, HttpServletResponse resp) {...}
    protected void doOptions(HttpServletRequest req, HttpServletResponse resp) {...}
    protected void doTrace(HttpServletRequest req, HttpServletResponse resp) {...}
}
  • Servlet을 기반으로 HTTP 프로토콜을 지원
  • HTTP 요청 처리에 특화된 기능 제공
  • GET, POST, PUT, DELETE, HEAD, OPTION, TRACE 등 을 구현

HttpServlet Service

protected void service(HttpServletRequest req, HttpServletResponse resp) {
    String method = req.getMethod();
    if (method.equals(METHOD_GET)) {
    ...
        doGet(req, resp);
    } else if (method.equals(METHOD_HEAD)) {
    ...
        doHead(req, resp);
    } else if (method.equals(METHOD_POST)) {
        doPost(req, resp);
    } else if (method.equals(METHOD_PUT)) {
        doPut(req, resp);
    } else if (method.equals(METHOD_DELETE)) {
        doDelete(req, resp);
    } else if (method.equals(METHOD_OPTIONS)) {
        doOptions(req, resp);
    } else if (method.equals(METHOD_TRACE)) {
        doTrace(req, resp);
    }
}
  • Request로부터 Method를 추출함
  • request method에 따라서 doGet, doHead, doPost, doPut, doDelete, doOptions, doTrace 등 수행

3. Spring MVC

DispatcherServlet

public class DispatcherServlet extends FrameworkServlet {
    @Override
    protected void doService(HttpServletRequest request,
                             HttpServletResponse response) {
    ...
        doDispatch(request, response);
    }
}
  • 클라이언트의 요청을 적절한 컨트롤러에게 전달한다.
  • 프론트의 컨트롤러 패턴을 구현
  • HttpServlet을 상속하여 모든 요청을 doDispatch 호출하게 변경
  • HandlerMapping, HandlerAdapter, ViewResolver 등 상호작용함.

4. Spring Security

AbstractAuthenticationProcessingFilter

public class CustomAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
    public CustomAuthenticationFilter(String defaultFilterProcessesUrl) {
        super(defaultFilterProcessesUrl);
    }
    @Override
    public Authentication attemptAuthentication(
            HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        UsernamePasswordAuthenticationToken authRequest =
                new UsernamePasswordAuthenticationToken(username, password);
        return getAuthenticationManager().authenticate(authRequest);
    }
    @Override
    protected void successfulAuthentication(
            HttpServletRequest request, HttpServletResponse response,
            FilterChain chain, Authentication authResult) {
        SecurityContextHolder.getContext().setAuthentication(authResult);
    }
}
  • Spring 프레임워크에 보안을 제공
  • 인증(Authentication), 인가(Authorization) 관련된 기능
  • 보안 작업을 수행하는 Servlet filter
  • SecurityContextHolder를 이용해서 인증(authentication) 설정

SecurityContext

  • Authentication 객체가 보관되는 저장소 역할. 필요시 SecurityContext로부터 Authentication 객체를 꺼내서 사용할 수 있다.
  • 각 스레드마다 할당되는 고유 공간인 ThreadLocal에 저장되기 때문에 동일한 스레드인 경우 필요한 아무 곳에서나 참조가 가능하다.
  • 즉, 서버에 접속해서 생성되는 각 Thread는 각각의 ThreadLocal에 SecurityContext를 가지고 있다.
  • SecurityContext는 ThreadLocal에 저장되어 있으면서 동시에 HttpSession에도 저장되어 있음.

SecurityContextHolder

public class SecurityContextHolder {
    ...

    private static void initializeStrategy() {
    ...
        if (!StringUtils.hasText(strategyName)) {
            // Set default
            strategyName = MODE_THREADLOCAL;
        }
    ...
        // Try to load a custom strategy
        try {
            Class<?> clazz = Class.forName(strategyName);
            Constructor<?> customStrategy = clazz.getConstructor();
            strategy = (SecurityContextHolderStrategy) customStrategy.newInstance();
        }
    }

    public static SecurityContext getContext() {
        return strategy.getContext();
    }
}
  • ThreadLocal의 전략을 사용할 수 있는데 기본적으로 MODE_THREADLOCAL 전략을 사용(스레드당 SecurityContext 객체를 할당)
  • MODE_THREADLOCAL 인 경우, ThreadLocalSecurityContextHolderStrategy 전략을 사용
  • SecurityContext를 ThreadLocal에 저장

5. Spring Data

  • 동기 blocking 하게 동작하여 쓰레드당 하나의 db 요청을 처리함.
  • Spring JDBC: JDBC를 사용하여 관계형 데이터베이스와 연결
  • Spring JPA: Java Persistence API (JPA)를 사용하여 관계형 데이터베이스와 연결

정리

  • Thread-per-request 모델을 사용하여 요청이 들어올때마다 쓰레드를 할당하여 여러 클라이언트 요청을 동시에 처리
  • SecurityContext를 ThreadLocal에 저장
  • 쓰레드당 하나의 db 요청을 처리
  • 요청이 들어올때마다 할당된 쓰레드는 spring mvc flow, 비즈니스 로직 수행, response 생성, SecurityContext 관리, db요청, http 요청 등 긴 활동주기를 갖는다.

Reference: Spring WebFlux 완전 정복 (FastCampus 강의)

profile
평범한 백엔드 개발자

0개의 댓글