서블릿(Servlet)? 어떻게 동작하고 언제 사용하지?

전홍영·2023년 6월 8일
0

Java

목록 보기
9/15

만약 개발자가 웹 어플리케이션 서버 즉, WAS를 직접 다 구현하려면 굉장히 많은 리소스가 소모되어야 할 것이다. HTTP 메시지를 연결하는 코드, HTTP 메시지를 파싱하고 어떤 비즈니스 로직을 실행해야 하는지에 대한 코드, 등등 많은 코드가 필요하다. 이러한 비효율적인 업무를 대신해줄 서블릿이 등장하였다.

서블릿

특징

@WebServlet(name = "Servlet",urlPatterns ="/servlet" )
public class Servlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //어플리케이션 로직
    }
}

위의 코드는 자바에서 제공하는 HttpServlet 클래스를 상속받아 서블릿을 구현한 코드이다.

  • URL이 호출되면 서블릿 코드(위의 service 메소드)가 실행된다.
  • HTTP 요청 정보를 편리하게 사용할 수 있는 HttpServletRequest 제공한다. 이를 통해 HTTP 메시지의 바디나 헤더의 정보를 가져올 수 있다.
  • HTTP 응답 정보를 편리하게 사용할 수 있는 HttpServletResponse 제공한다. HTTP 응답시 HTTP 스펙에 맞춰 자동으로 HTTP 응답 메시지를 작성해 준다.
  • 개발자는 HTTP 스펙을 아주 편리하게 사용할 수 있다.

서블릿 컨테이너

서블릿 컨테이너는 서블릿 객체를 생성하고, 초기화하고, 호출, 종료하는 생명주기를 관리해주는 역할을 한다. 위의 코드처럼 서블릿을 생성하면 서블릿 컨테이너에 등록되는 것이다.

중요한 점!! 서블릿 객체는 싱글톤으로 관리가 된다. 고객의 요청이 올 때마다 계속 객체를 생성하는 것은 굉장히 비효율적이기 때문에 최초에 로딩될 때 객체를 미리 만들어두고 재활용한다. 따라서 모든 요청은 동일한 서블릿 객체 인스턴스에 접근하게 된다. 그래서 공유변수를 주의 해야한다.

서블릿의 동작

동작 과정

클라이언트가 WAS에 요청메시지를 보내면 WAS는 해당 요청메시지를 기반으로 응답메시지를 만든다. 그후 서블릿 컨테이너에 요청메시지가 호출한 서블릿을 호출하여 로직을 실행한후 그 결과를 미리 만들어놓은 응답메시지에 담아 보낸다.

요청

HTTP 요청시 다양한 형태로 데이터가 서블릿으로 넘어온다. 예를 들어 body에 데이터가 있을 수 있고 헤더나, 파라미터로 데이터가 넘어올 수 있다. 예를 들어 다음 코드를 보자.

@WebServlet(name = "requestBodyJsonServlet",urlPatterns ="/request-body-json" )
public class RequestBodyJsonServlet extends HttpServlet {
    //json 라이브러리를 통하여 파싱
    private ObjectMapper objectMapper = new ObjectMapper();
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletInputStream inputStream = request.getInputStream();
        String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);//스트림을 이용하여 데이터 스트링으로 반환
        System.out.println("messageBody = " + messageBody);
        HelloData helloData = objectMapper.readValue(messageBody, HelloData.class);
        System.out.println("helloData.getUsername() = " + helloData.getUsername());
        System.out.println("helloData.getAge() = " + helloData.getAge());
    }
}

@Getter
@Setter 
public class HelloData {
    private String username;
    private int age;
}

이처럼 HttpServlet을 상속받은 서블릿을 생성하여 서블릿 컨테이너에 등록하면 위의 코드처럼 request에서 데이터의 바디를 파싱하여 이 데이터를 조작할 수 있게된다. 다른 방법도 다 HttpServlet을 상속 받은 후 해당 방식에 따라서 데이터를 파싱하거나 가져올 수 있다.

응답

응답도 요청과 마찬가지로 HttpServlet을 상속받은 서블릿을 생성하여 데이터를 조작하여 HttpServletResponse에 담아 보낼 수 있다. 이때 Json객체를 바디에 담아 보낼 수도 있고, html이나 헤더에 데이터를 담아 보낼 수 있다.

다음 코드는 response의 헤더를 설정하고, Json 데이터를 담아 보내도록 서블릿을 구성한 코드이다.

@WebServlet(name = "reponseJsonServlet", urlPatterns = "/response-json")
public class ResponseJsonServlet extends HttpServlet {
    ObjectMapper objectMapper = new ObjectMapper();
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //Content-Type : application/json
        response.setContentType("application/json");
        response.setCharacterEncoding("utf-8");
        HelloData helloData = new HelloData();
        helloData.setAge(20);
        helloData.setUsername("kim");
        //{"username":"kim", "age":20}
        String result = objectMapper.writeValueAsString(helloData);
        response.getWriter().write(result);

    }
}

동적인 html을 반환하고 싶다면?

서블릿은 JSP와 thymleaf 같은 템플릿 엔진을 사용하여 동적인 html을 반환할 수 있다. 만약 서블릿 안에 html코드를 작성하게 된다면 정적인 html을 만들 수는 없을 것이다. 따라서 템플릿 엔진을 많이 사용하는데 템플릿 엔진을 이용하게 되면 html 코드 안에 자바 코드를 넣을 수 있어 필요한 부분만 동적으로 변경할 수 있다. html에 자바 코드를 넣어 해당 부분이 서버 내부에서 서블릿으로 변환된다.

이렇게 템플릿 엔진을 이용하여 서블릿만을 이용하여 html을 반환할 때보다 동적이고 깨끗하게 코드를 작성할 수 있다. 하지만 이러한 부분이 문제가 되는데, 중요 비즈니스 로직이 노출되고, 너무 많은 양의 코드가 템플릿 엔진 속에 들어가기 때문에 굉장히 복잡하고 유지보수가 힘들것이다.

결론

이와 같이 서블릿을 이용하면 WAS를 통해 HTTP 프로토콜을 연결하고 종료하는 중요한 비즈니스 로직이 아닌 코드를 개발자가 작성할 필요없이, 쉽게 HTTP 통신이 가능하게 된다.

또한 템플릿 엔진을 이용하면 동적인 웹사이트도 제공이 가능하게 되었다. 그러나 이는 한계점과 몇몇 단점이 존재한다.

profile
Don't watch the clock; do what it does. Keep going.

0개의 댓글