끊임없이 검증하라

나에게 당연할지라도

Spring

Spring_정리3_Spring의 구조 훑어보기_서블릿

fadet 2022. 5. 5. 16:57

※ 이 포스트는 스프링 실습 과정에서 작성하기 때문에 정보가 부정확할 수 있는 부분이 있습니다.

특히 Spring의 전체적인 이해를 돕기 위해 논리의 비약이나 내용 축약으로 인한 정보의 질적저하가 있을 수 밖에 없습니다. 따라서 전체 흐름 이해를 위한 참고만 해주시고 틀린 부분이 있을 경우 알려주시면 감사하겠습니다.

 

 이번 포스트는 김영한님의 '스프링 MVC 1편 - 백엔드 웹개발 핵심 기술' 강의를 수강하고 배운 내용을 정리하여 작성하였습니다. 따라서 스프링에 대해 더 자세히 공부하고 싶으신 분은 인프런에서 해당 강의를 수강하시길 추천합니다. 

❗ 이전 글에서 이어집니다! 따라서 잘 이해가 안되신다면 이전 글을 읽고 와주세요!

* 잘 모르시는 기술은 로그인 필요 없이 이 곳에서 AI에게 물어보세요!   

 


이전 포스트에선 스프링의 탄생 과정까지를 JAVA의 시작부터 차근차근 알아보았습니다. 이번 포스트에선 스프링 mvc의 구조를 알아보기 전에 스프링 작동 핵심인 서블릿에 대해 잠시 알아보겠습니다.

 

스프링 MVC와 서블릿

 

우선 저번 글을 보고 오셨다면 직접 서블릿을 사용해서 페이지를 반환하는 방식은 현재 더 이상 사용하지 않는다고 알고계실겁니다. 하지만 현재 스프링을 공부하시거나 사용 중인 분들이시라면 아직도 스프링 코드를 짜면서 서블릿이라는 내용이 포함된 코드를 많이 보셨을 것입니다. 이는 현재 스프링 MVC에선 서블릿을 직접 다루진 않지만 스프링이 작동하는 내부 구조를 살펴보면 여전히 서블릿이 맞물려 돌아가기 때문입니다.

 

우리가 전자 제품을 사용할 때 리모콘이나 버튼 같은 인터페이스를 통해 기능을 조작합니다. 우리가 조작하는 과정에 전류에 대한 제어는 포함되어 있지 않습니다. 하지만 전자 제품은 전류 없이는 작동하지 않습니다. 따라서 단순한 조작으로 제품을 사용하는 것은 전자 제품을 만드는 과정에서 얼마의 전압을 가했을때 전류가 흐르고 정해진 전력을 소모하도록 미리 설계해놨기 때문에 가능합니다. 마찬가지로 스프링 MVC도 동일합니다. 스프링이라는 웹 프레임워크를 만들때 이런 로직에는 어떤 서블릿이 어떻게 작동하는지 미리 코드로 설계되어 우리가 직접 스프링을 사용할 때는 MVC와 관련된 컴포넌트만 다루면 빌드가 가능합니다.  javax.servlet에 가서 Servlet 인터페이스 docs를 보면 이런 코드가 있습니다. 

public interface Servlet {

    /**
     * Called by the servlet container to indicate to a servlet that the servlet
     * is being placed into service.
     *
     * <p>
     * The servlet container calls the <code>init</code> method exactly once
     **/
	...
    public void init(ServletConfig config)
	...
    public ServletConfig getServletConfig();
	...
    public void service(ServletRequest req, ServletResponse res)
    ...	
    public void destroy();
}

우리는 이런 메소드들을 직접 본 기억이 거의 없습니다. 그것은 스프링 프레임워크 내에 서블릿의 작동에 대한 것은 미리 코드로 다 짜여 있고 컴포넌트를 사용함으로써 우리는 간접적으로 서블릿을 사용한다고 생각하면 됩니다. 전자 제품을 작동시키는 동력이 있듯이 서블릿이 있기에 스프링이 작동하고 그 과정은 우리 눈에 보이지 않는다고 이해하셨다면 좋겠네요.

 

서블릿이 이렇게 우리 눈에 보이지 않고 작동하니 스프링 컴포넌트만 다루는 우리는 미리 작성된 스프링의 편리한 기능만 이용해서 빌드가 가능하기에 눈부시게 획기적인 생산성 향상이 가능했습니다. 하지만 명암은 어디에나 있듯이 서블릿을 직접 다루지 않는 것도 단점이 없지는 않습니다. 만약 우리가 코드를 짜다가 버그가 발생했을때 스택 트레이스*를 보고 디버깅을 하려는데...

 

어... 어?

 

'나는 서블릿을 직접 다뤄본 적이 없는데 이 예외를 처리하려면 어느 부분을 손대야하지...' 라는 생각을 한 적이 한 두 번 있을 것입니다. 이는 비단 서블릿에서만의 문제가 아닌 근본 기술에 대한 이해 없이 편리한 기능만 사용할 때 자주 겪는 상황입니다.

* 스택 트레이스(Stack trace) : 프로그램이 시작된 시점부터 현재 위치 까지의 메서드 호출 목록

보통 run console에 뜨는 오류 메시지에 자주 등장

 

그렇기 때문에 이런 장애 대응을 위해서 스프링을 사용하는 우리는 스프링의 기능들을 숙달하는 것도 중요하지만 서블릿에 대한 기본적인 이해를 할 필요가 있습니다. 따라서 이번 포스트에선 서블릿의 전체적인 흐름을 다뤄볼 것이고 서블릿에 대한 이해가 조금 생긴 후에는 서블릿 관련 장애 대응뿐만 아니라 스프링의 전체적인 이해를 위해 서블릿과 스프링 MVC가 어떻게 작동하는지, 그리고 스프링 MVC가 어떻게 변화해 왔는지를 살펴보려고 합니다.

 

서블릿의 생명주기

 

JAVA Servlet, 흔히 서블릿이라고 많이 부르는 이것은 이전 포스트에서 대략 설명한대로 동적인 페이지를 생성해주는 JAVA 프로그램입니다만 서블릿의 생성부터 다루기 위해선 사실 서블릿을 하나의 JAVA Object라고 생각하는게 맞지 않나 싶습니다. JAVA에서 객체가 생성될때 1 특정 인터페이스를 상속받은 2 특정 클래스를 바탕으로 3 객체가 생성 이라는 과정을 거치듯이 서블릿 역시 1 특정 서블릿 인터페이스를 상속받은 2 특정 서블릿 클래스를 바탕으로 3 서블릿 객체가 생성 되는 동일한 과정을 거칩니다.

 

우리는 외부 dependency를 받아 수없이 많은 라이브러리의 도움을 받아 우리는 웹을 빌드합니다. 그 과정에서 우리가 라이브러리를 어떻게 사용할 수 있는지, 또 그런 라이브러리들을 쉽게 쓸 수 있게 해주는 이 스프링은 어떻게 이뤄지는지 알고 계신가요? 스프링을 사용하시는 대부분이 사용하셨을 @SpringBootApplication을 들여다보면

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
      @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

이렇게 수없이 많은 어노테이션들로 구성되어 있고 저 어노테이션들도 들여보다 보면 알게 될겁니다. '아 결국 우리가 사용하는 기능들은 사용할때마다 직접 작성하는 대신 미리 작성해놓은 코드들이구나'라는 것을요. 이 얘기를 한 이유는 어노테이션이 중요한 것이 아니라 서블릿 역시 이와 마찬가지로 미리 작성된 코드를 바탕으로 작동한다는 것을 보여주기 위해서입니다. 

 

public interface Servlet {
	...
    public void init(ServletConfig config) throws ServletException;
	...
    public ServletConfig getServletConfig();
    ...
    public void service(ServletRequest req, ServletResponse res)
            				throws ServletException, IOException;
	...
    public void destroy();
}

맨 처음에 보여드렸던 서블릿 인터페이스입니다. 이 인터페이스의 메소드들은 서블릿의 생명주기를 알려줍니다. 이 인터페이스를 상속받은 서블릿 클래스들은 서블릿 컨테이너에 등록되고 사용자의 요청에 의해 서블릿을 실행해야하면 등록된 클래스 정보를 바탕으로 서블릿 객체가 생성되고 서비스 메서드를 수행한 뒤 서블릿 객체가 소멸합니다. 하나 더 중요한 것은 이 생명주기의 흐름을 개발자가 직접 관리하는 것이 아닌 컨테이너가 관리 주체가 되는데 이 특성이 스프링의 핵심 중 하나인 IoC(제어의 역전)을 나타냅니다. IoC는 나중 포스트에서 더 자세히 다루도록 하겠습니다.

 

# 프로세스와 쓰레드, 쓰레드풀

 

서블릿의 생명주기에 대해 간단히 알아보았는데 아직은 궁금한게 더 남아있습니다. 도대체 어떻게 컨테이너가 서블릿을 관리하길래 앞서 언급된 CGI보다 서블릿의 성능이 좋은 것일까요? 이를 알기 위해선 일단 프로세스와 쓰레드에 대한 기초적인 이해를 해야할 필요가 있습니다. 하지만 이 둘을 제대로 다루는 것은 전혀 짧지 않기 때문에 정말 간단히 설명하고 가겠습니다.

 

지금 우리가 C드라이브에 .exe파일을 실행한다고 가정합시다. .exe파일을 더블클릭하여 실행했고 화면에 창이 띄워졌습니다. 이 때 드라이브에 저장된 .exe 파일을 프로그램이라고 합니다. 그리고 이 프로그램을 더블클릭하여 실행하면 컴퓨터의 실행 전반을 관리하는 OS가 실행을 위한 자원을 예약하고 자원을 소모하여 CPU가 연산을 진행해서 프로그램이 실행 중이 되면 이를 프로세스라고 합니다. 그렇기에 프로세스 창을 보면 저렇게 CPU를 얼마나 소모하고 있으며 메모리를 얼마나 잡아먹는지를 알려줍니다. 다시 말해 프로세스는 OS에게 작업을 할당받은 작업의 단위입니다.

 

그런데 프로세스를 하나 실행할 때마다 OS는 일정 메모리를 할당해줘야하고 CPU가 언제 작업해야 하는지 스케쥴링을 해주는 등 비용 지출이 꽤나 큽니다. 그런데 위 사진만 봐도 우리가 컴퓨터를 사용할 때 얼마나 많은 프로세스를 실행하는지 알 수 있습니다. 이 때 무거운 프로그램의 경우 프로세스 하나로는 버거울 때가 존재합니다. 식당으로 예를 들면 요리사 한 명에게 테이블을 하나씩 배정해주었는데 그 요리사에게 너무 많은 조리를 시키면 테이블 하나로는 충분하지 않습니다. 그렇다고 테이블을 같은 테이블을 하나 더 배정해주면 소화는 가능하겠지만 식당은 식당대로 요리사는 요리사대로 부담스럽습니다. 그럴때 테이블에 수도는 하나 공유하되 레인지를 두배로 늘려서 해결하는 것이 낫습니다.

식당 예시

 

이 예시에서 프로세스를 하나의 테이블, 쓰레드를 레인지, 수도를 메모리라고 생각하면 됩니다. 프로그램이 거대하다면 프로세스 수를 늘리는 것이 아닌 수도처럼 공유가 가능한 부분은 메모리를 프로세스 단위로 할당하여 그 안에서 공유하고 스택이나 상태 등의 각각 처리해야할 부분은 개별 정보를 갖는 쓰레드를 여러 개 생성하여 처리하면 비용적으로 큰 이득을 누릴 수 있습니다. 한마디로 쓰레드는 프로세스의 실행 단위입니다. 아래 그림을 참고하시되 컨텍스트 스위칭 등 CS 중요 용어 관련해 더 자세한 내용은 OS에 관한 포스트에서 다루겠습니다.

 

프로세스와 쓰레드에 알아봤는데 이것을 알아본 이유는 서블릿의 실행에 쓰레드가 관여하기 때문입니다. 이전 포스트에서 알아본 CGI는 요청당 하나의 프로세스가 실행됩니다. 하지만 서블릿의 경우 요청이 오면 미리 실행되어 있는 프로세스 내에서 새로운 쓰레드가 하나 생성이 되고 그 쓰레드가 서블릿을 호출합니다. 

 

그런데 이 방식도 문제가 있습니다. 쓰레드가 프로세스에 비해 생성 비용이 적게 든다고 하더라도 요청이 올 때마다 무한정 생성한다면 서버가 버티지 못할겁니다. 그렇기때문에 WAS는 쓰레드 풀이란 공간을 생성하고 미리 사용될 쓰레드를 일정량 만들어 보관해둡니다. 그리고 요청이 올 때마다 쓰레드 풀에서 하나씩 꺼내 사용하게 됩니다.

 

김영한님의 '스프링 mvc 백엔드 핵심 웹기술 1편' 중에서

 

 

서블릿의 역할

 

지금껏 서블릿이 생성되어 호출되는 과정까지를 살펴보았습니다. 이제 우리에게 드는 의문은 '어떻게 생기는 지는 알았는데... 그래서 하는 일이 정확히 뭔데?'입니다. 앞서 우리는 서블릿이 요청을 받아 동적 페이지를 생성한다고만 들었습니다. 하지만 이 말만 듣고는 서블릿이 어떤 과정으로 페이지를 생성하는지 알 턱이 없습니다. 그렇기 때문에 서블릿의 역할부터 작동 원리까지를 살펴보겠습니다.

 

일단 서블릿이 하는 일을 좀 더 정확히 파악하기 위해 우리가 사용자로부터 POST 요청을 받을 때 수행되는 과정을 살펴보면 다음과 같습니다.

  • 서버 TCP/IP 연결 대기, 소켓 연결
  • HTTP 요청 메시지를 파싱 (POST 방식, /save URL 인지 Content-Type 확인 HTTP 메시지 바디 내용 파싱)
  • 비즈니스 로직 실행 → 데이터베이스에 저장 요청
  • HTTP 응답 메시지 생성
  • TCP/IP에 응답 전달, 소켓 종료

과정은 꽤나 길지만 실제로 요즘 개발자들이 스프링으로 코딩하는 부분은 저 한 단계가 대부분입니다. 결국 나머지 단계는 누군가 대신해준다는 것이고 이 일을 해주는 것이 서블릿입니다. 이제 서블릿을 사용하는 것이 개발자들에게 좀 더 비즈니스 로직에 집중할 수 있도록 만들어준다는 설명을 할 수 있게 됐네요.

 

앞선 과정을 통해 서블릿이 HTTP 요청과 응답에 대한 파싱을 개발자들 대신 처리해준다는 것을 알았습니다. 서블릿이 무엇을 하는지 알았다면 이제 서블릿이 어떻게 생겼는지 그 계층 구조를 살펴볼 시간이 왔습니다. 하지만 구조가 복잡한 편이라 다 알아볼 필요는 없고 이해를 위해 꼭 필요한 단계만 보겠습니다.

일단 서블릿 역시 JAVA Object기에 모든 서블릿들의 부모는 Object입니다. 이를 Servlet Interface와 ServletConfig가 상속하며 앞서 봤다시피 Servlet Interface에는 서블릿의 생성, 설정, 서비스 실행, 소멸까지의 생성 주기 메소드가 있고 ServletConfig는 서블릿 객체가 생성될 때 입력되어야할 정보의 초기화에 관련된 메소드가 존재합니다. 이 Interface 들의 바로 다음엔 GenericServlet이라는 추상 클래스가 있습니다, 이 GenericServlet은 직접 사용하지 않으니 이 클래스는 프로토콜에 독립적이라는 것만 알고넘어가겠습니다.

 

중요한 건 GenericServlet를 상속받는 HttpServlet이란 놈입니다. HttpServlet는 GenericServlet에서 상속받은 메서드들을 오버라이딩하고 프로토콜에 독립적이었던 GenericServlet과는 달리 웹 통신의 표준인 HTTP 프로토콜을 사용하는 추상 클래스입니다. 일반적인 HTTP 통신 환경에서 개발하는 우리는 이 추상 클래스를 상속 받은 서블릿 클래스부터 직접 서블릿 객체를 사용할 수 있게 되며 이 클래스는 다음 포스트까지 게속 중요하게 다뤄지니 꼭 기억해주세요.

 

사실 서블릿의 계층 구조는 앞서 말했듯 이보다 더 복잡하지만 이정도만 알고 넘어가도 무방합니다. 이제 서블릿의 역할과 그 역할을 수행하기 위해 어떤 상속 구조를 갖는지 살펴보았으니 실제로 어떻게 작동하는지 알아보도록 하겠습니다.

 

서블릿의 작동 원리

 

# 서블릿의 작동 사이클

 

우리가 앞서 살펴본 내용 중 서블릿의 관리에 대해 짧게 정리해보면 서블릿의 생성부터 소멸까지의 관리는 서블릿 컨테이너에게 위임하므로 우리는 서블릿의 service 메소드(비즈니스 로직)만 작성해주면 됨 입니다. 하지만 이것과 서블릿의 역할을 안다고 우리가 서블릿의 작동 원리를 파악했다고 할 수는 없습니다. 따라서 웹 통신 중 서블릿이 어떤 과정을 거치는지 알아보도록 하겠습니다.

 

우선 서블릿을 다루기 시작한 초기부터 살펴보기에는 너무 내용이 길기때문에 오히려 지금의 mvc패턴까지 함께 이해하려는 우리에게 도움이 되지 않습니다. 따라서 어느 정도 지금의 개발 구조에 다가간 시점부터 시작하겠습니다. 

 

public class FirstServlet extends HttpServlet {
	
	public void init(ServletConfig config) throws ServletException {
		System.out.println("init() 실행");
	}

	public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("service() 실행");
	}
}

위의 코드를 살펴보겠습니다. 우리가 처음 보게될 서블릿인 FirstServlet은 언급한대로 HttpServlet을 상속받습니다. 이 서블릿에서 처음해야 할 것은 서블릿의 생성에 필요한 init 메소드를 작성하는 것입니다. 과거의 서블릿은 사용자 요청을 어떤 서블릿에 연결해줘야 하는지 알려줬어야 했습니다. 따라서 서블릿의 초기화 메소드인 init은 서블릿 생성시 초기화 설정 정보인 ServletConfig를 인자로 받습니다. 이 ServletConfig는 서블릿 생성시 필요한 인자와 web.xml*에 작성된 서블릿의 이름, 접근 url 등의 메소드를 갖고 있습니다. 이제 서블릿이 실행되면 콘솔창에 'init() 실행'이라는 문장이 올라올 겁니다.

XML(eXtensible Markup Language):특수한 목적을 갖는 마크업 언어를 만드는데

사용하도록 권장하는 다목적 마크업 언어

주로 파싱 설정 파일 등에 많이 사용

 

// web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" version="4.0">
  <display-name>fadet</display-name>
    
  <servlet>
  	<servlet-name>first</servlet-name>
  	<servlet-class>fadet.servlet.v1.FirstServlet</servlet-class>
  </servlet>
  
  <servlet-mapping>
  	<servlet-name>first</servlet-name>
  	<url-pattern>/hello</url-pattern>
  </servlet-mapping> 
</web-app>

이제 초기화를 통해 Client의 request가 오면 해당 서블릿으로 전해줍니다. 그 다음으로 해야할 일은 서블릿의 비즈니스 로직을 지정해주는 service 메소드의 작성입니다. 일단 우리의 코드는 콘솔창에서 서블릿이 작동하는지 알아보기 위한 간단한 예제이므로 서블릿이 작동할 때 콘솔창에 'service() 실행' 문장이 올라올겁니다. http://localhost8080/fadet/hello URL로 접속하여 새로고침을 몇 번하면 아래와 같이 콘솔창에 서블릿이 최초 한 번 생성되고 service가 여러 번 실행되는 결과가 뜰 겁니다. 

 

콘솔창 메세지

 


# HttpServletRequest와 HttpServletResponse

 

앞서 서블릿의 작동 사이클을 크게 봤는데 아직 서블릿이 HTTP 요청을 파싱해주는 과정은 어디에도 없었습니다. 그렇기 때문에 우리는 service의 인자로 받는 HttpServletRequest와 HttpServletResponse을 살펴보겠습니다. 앞서 개발자가 요청과 응답 과정에서 html과 JAVA로 각각 파싱하는 과정을 서블릿이 대신해준다고 살펴봤습니다. 여기서 서블릿이 HTTP 요청을 JAVA 코드로 파싱한 결과를 HttpServletRequest 객체에 담아 제공하고 HttpServletResponse 객체에 JAVA코드를 담아놓으면 사용자 응답에 맞춰 파싱해 줍니다. 

 

HttpServletRequest를 사용함으로 개발자는 HTTP 요청을 매우 편리하게 조회할 수 있으며 조회할 수 있는 정보로는  HTTP 요청의 Start-line(HTTP 메소드, URL, 쿼리스트링, 스키마&프로토콜), Header, Body 등이 있습니다. HTTP 메소드는 Get,Post등의 요청 방식, 쿼리스트링은 '/?type=post&returnURL=...'처럼 URL에 정보를 담는 것을 뜻합니다. 주로 getX을 통해 조회하여 객체화합니다.

// getX() 메소드를 통해 객체화
String method = request.getMethod()
String URI = request.getRequestURI()
String userName = request.getParameter("userName")
...

 

 

HttpServletResponse의 경우 서블릿 안에서 사용자에게 응답으로 파싱될 데이터의 HTTP 응답 코드, Content-type, Header, Body 등을 지정해줍니다. 주로 setX을 통해 JAVA코드로 지정해주고 getWriter로 페이지를 작성합니다.

// setX 메소드를 통해 응답메시지의 정보 지정
response.setStatus(HttpServletResponse.SC_OK);
response.setHeader("Content-Type", "text/plain;charset=utf-8");
...

// 실질적인 페이지 작성
PrintWriter w = response.getWriter();
w.write("<html>\n" +
         ...
        "</html>");

 


# @WebServlet

 

이제 우리는 서블릿을 사용할 수 있지만 뭔가 부족합니다. 매번 서블릿을 사용할때마다 서블릿의 이름을 정해줘야하고 url을 매핑해줄 설정파일을 작성하는 것은 너무나 불편합니다. 따라서 이후 더 자세히 다뤄볼 어노테이션을 이용하여 이 XML 설정파일을 대신할겁니다. 어노테이션(Annotation)은 사전적으로는 주석이라는 의미지만 JAVA, Spring에선 중요한 기능으로 사용됩니다. 보통 '@어노테이션명'으로 클래스, 메소드, 필드 상단에 작성되며 각 어노테이션들은 미리 JAVA코드로 해당 로직을 구현해두고 필요할 때마다 사용하여 복잡한 설정이나 코드를 줄여주는 역할을 합니다. 지금은 간단하게 설명하고 넘어가지만 중요한 내용이기에 이후 다시 언급겠습니다.

 

우리는 불편한 web.xml을 작성하는 대신 @WebServlet을 사용하겠습니다.

@WebServet(name = "firstServlet", urlPatterns = "/hello")
public class FirstServlet extends HttpServlet {
	...

​해당 어노테이션을 클래스 상단에 작성하면 설정파일에 작성해야할 서블릿 이름과 url을 간편하게 작성할 수 있습니다. name의 경우 클래스 이름과 같을 경우 생략 가능하므로 실질적으론 url만 입력해도 됩니다.

 

이 @WebServlet을 사용하면 서블릿의 초기화 시점에 ServletConfig를 받는 과정을 어노테이션이 해주게 되어 서블릿의 init 메소드를 더 이상 작성할 필요가 없게됩니다. 

public class FirstServlet extends HttpServlet {
	// 생략
	// public void init(ServletConfig config) throws ServletException {
	//	System.out.println("init() 실행");
	// }

	public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("service() 실행");
	}
}

 


 

# 정리

 

앞선 과정까지 모두 이해하셨다면 아래 코드로 서블릿의 작동 원리를 한 흐름으로 알아보겠습니다. 아래 코드의 경우 URL(http://localhost8080/fadet/hello?userName='name')로 사용자가 페이지를 요청할 경우 작동할 서블릿을 만든 것이고 해당 코드는 절대 작동하지 않는 잘못된 코드이지만 의사코드처럼 내용의 이해를 돕기 위해 작성한 코드입니다.

// 이해를 돕기 위한 코드입니다(절대 작동하지 않는 잘못된 코드)
@WebServlet(name = "firstServlet", urlPatterns = "/hello")
public class FirstServlet extends HttpServlet {
	...
	public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
    	
        String userName = request.getParameter("userName");
        
        Member member = new Member(userName);
        memberRepository.save(member)
        
        response.setContentType("text/html");
        response.setCharacterEncoding("utf-8");
        
        PrintWriter w = response.getWriter();
        w.write("<html>\n" +
        		...
                "</html>");
1 사용자로부터 HTTP 요청이 오면 @WebServlet에 작성된 name과 url을 비교해 같다면 해당 서블릿이 생성
2 서블릿의 service 메소드가 request, response를 인자로 받아서 호출, 서블릿이 이 객체들의 파싱 과정을 대신 해주어 개발자들은 이 객체들을 JAVA 코드로 다루기만 하면됨
#request 
3 request.getParameter를 통해 요청으로 넘어온 파라미터를 객체화(userName)
4 사용자 객체(member)를 미리 객체화된 userName을 인자로 생성하여 memberRepository를 통해 DB에 저장
#response
3 response.setContentType 등을 통해 응답 메세지의 유형을 결정
4 response.getWriter > w.writer를 통해 응답될 페이지의 html을 직접 작성

 

이렇게 이번 포스트에선 서블릿을 중점적으로 다뤄봤는데 앞에서 언급했듯 서블릿을 제대로 알기위해선 이것으론 한참 부족합니다. 실제로 서블릿의 자세한 작동 원리나 메소드들의 사용법 등 조금 어려울 수 있는 내용은 생략했습니다.하지만 앞으로 우리가 살펴볼 mvc 패턴에서 서블릿이 작동하는 과정을 이해하는데는 이정도면 충분하다고 생각합니다. 

 

다음 포스트에선 지금껏 알아본 서블릿이 왜 직접 사용되지 않는지와 서블릿이 mvc 패턴과 어떻게 결합되는지를 살펴보겠습니다.

 

refer

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1/dashboard

 

스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 인프런 | 강의

웹 애플리케이션을 개발할 때 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. 스프링 MVC의 핵심 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., -

www.inflearn.com

https://studyandwrite.tistory.com/459

 

[스프링/Spring] 서블릿(Servlet)과 서블릿 컨테이너

0. 들어가면서 자바 웹 기술 역사를 살펴보면 서블릿은 JSP보다도 이전에 생긴 근본적인 개념입니다. 아래에서 서블릿에 대해 자세히 기술하겠지만, 서블릿을 공부하다보면 그 당시 개발자들이

studyandwrite.tistory.com

https://velog.io/@jakeseo_me/%EC%9E%90%EB%B0%94-%EC%84%9C%EB%B8%94%EB%A6%BF%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90.-%EA%B7%BC%EB%8D%B0-%ED%86%B0%EC%BA%A3%EA%B3%BC-%EC%8A%A4%ED%94%84%EB%A7%81%EC%9D%84-%EC%82%B4%EC%A7%9D-%EA%B3%81%EB%93%A4%EC%9D%B8

 

자바 서블릿에 대해 알아보자. 근데 톰캣과 스프링을 살짝 곁들인

서블릿 이전에 CGI가 있었다. CGI(Common Gateway Interface)는 서블릿의 조상쯤 되는 기술이라고 생각하면 된다. CGI 이전의 웹서버는 단순히 사용자가 특정 경로를 입력하면 그 경로에 해당하는 리소스

velog.io

https://kgvovc.tistory.com/29

 

서블릿 구현 및 실행 (web.xml, @WebServlet 설정)

서블릿 구현 및 실행 서블릿 작성 <이클립스 디렉토리 구조> FirstServlet.java package com.edu.test; import java.io.IOException; import javax.servlet.*; import javax.servlet.annotation.WebServlet; impo..

kgvovc.tistory.com