이번 시간부터는 스프링 부트의 컨테이너리스, 서블릿 컨테이너와 관련된 번거롭고 복잡한 지식이나 작업을 요구하지 않고 우리는 스프링 컨테이너에 들어가는 애플리케이션 코드 빈이라고 불리는 컴포넌트 개발에만 집중을 하고 서블릿 컨테이너와 관련된 설치, 배포, 관리 등의 작업을 신경 쓰지 않도록 구성을 만들어 보는 작업을 할 것.

이거를 한꺼번에 이 모델을 딱 시작하려고 하면 굉장히 번거롭기 때문에 조금 작은 스탭을 밟아서 한 번 진행을 해볼 것.

일단 우리 관심사는 이 서블릿 컨테이너를 직접 설치하지 않고 어떻게 동작하게 만들 것이냐 그 다음에 우리가 여기에 대해서 직접 신경 쓰지 않도록 할 것이냐 이므로, 서블릿 컨테이너를 설치하는 대신에 stand-alone 프로그램을 만들 건데 그 stand-alone 프로그램에서 이 서블릿 컨테이너를 알아서 띄워주는 작업을 해야 된다.

서블릿 컨테이너는 컨테이너이므로 원래 이 안에 서블릿이 많이 들어가 있을텐데, 우리 관심사에서 지워야 되니까 서블릿 하나를 만드는 간단한 작업을 해볼 것. 그래서 웹 애플리케이션으로 동작하는 건 한 번 점검해봐야 한다. 이것만 집중을 하고 나머지 작업들은 앞으로 재사용해서 신경 쓰지 않도록 할 수 있는 코드로 한 번 구현해볼 것.

근데 이제 서블릿을 또 만드는데 서블릿은 보고 어떻게 개발하고 이 이야기를 해야 되니까 제일 쉬운 것부터 한 번 시작을 해보자. 일단 빈 서블릿 컨테이너를 코드로 띄워보는 작업을 해볼 것.

서블릿이라는 건 자바의 표준 기술이고 이 표준 기술을 구현하는 컨테이너 제품들이 많이 남아있다. 거의 서블릿 컨테이너의 대명사라고 할 만 한 게 Tomcat. 톰켓을 메인 메소드를 통해서 시작해볼 것.

톰켓은 그럼 어떻게 여기서 사용할 수 있고 설치하지 않고도 톰켓을 띄우게 할까? 톰켓도 자바로 만들어진 프로그램이고 결국 자바로 만들었다는 얘기는 어떤 클래스의 오브젝트를 만들고 그 안에 어떤 메소드를 실행하면 동작하기 시작할 거라는 이야기.

그 정보를 알면 되는데 원래 서버를 설치해서 사용하게 의도했던 톰캣도 있지만 필요하다면 이 톰캣을 Embed 해서 내장해 필요한 환경을 사용해도 좋다는 의도를 갖고 톰캣 개발자들이 Embedded Tomcat 이라는 내장형 톰켓 라이브러리를 제공해준다.

스프링 부트를 처음에 프로젝트를 Spring initializer 를 통해 만들었을 때 이미 Embedded Tomcat 이 우리 라이브러리에 들어와있다. 그것을 불러 시작해볼 예정.

@SpringBootApplication
public class HelloApplication {

  public static void main(String[] args) {
    new Tomcat().start(); // 물론 이렇게 간단하지는 않다.. 
  }
}

스프링 부트가 Tomcat Servlet 컨테이너를 내장해서 프로그램에서 코드로 쉽게 시작해서 사용할 수 있도록 만들어준 도우미 클래스인 TomcatServletWebServerFactory 가 있다.

@SpringBootApplication
public class HelloApplication {

  public static void main(String[] args) {
    ServletWebServerFactory serverFactory = new TomcatServletWebServerFactory();
	  WebServer webServer = serverFactory.getWebServer();
  }
}

Factory 란 이 자체가 앞에 있는 Tomcat Servlet 웹서버를 만드는 복잡한 생성 과정과 복잡한 설정 등을 지원하고 모든 설정을 마친 뒤에 Tomcat Servlet 웹서버를 생성해달라는 요청을 하면 그때 만드어주는 역할을 하는 도우미 클래스.

serverFactory.getWebServer() 이게 진짜 웹서버, Servlet 컨테이너를 만드는 생성 함수가 되는 것. 이걸 받으면 WebServer 라는 타입으로 받는다.

이름이 이제 Tomcat은 갑자기 사라지고 WebServer, getWebServer 이렇게 나온다. 이거는 이제 스프링 부트가 톰캣 외에 Jetty나 UnderTeo 같은 유명한 서블릿 컨테이너도 지원 할 수 있고 모두 일관된 방식으로 동작하도록 만들기 위해 추상화 해놨기 때문. 사실 리턴 타입은 앞에 Tomcat을 빼고 ServletWebServerFactory 타입을 받아도 된다.

이를 들어가 확인해보면 ServletWebServerFactory 를 구현한 클래스는 getWebServer 라는 걸 지원해야 하고 이 getWebServer 에서 리턴하는 게 웹서버 타입의 오브젝트인데 웹서버에 들어가 보면 start, stop, getPort , shutDownGracefully 등이 있다. 이게 Tomcat 이나 Jetty 등 특정한 서블릿 컨테이너에 구현이 종속되지 않게 추상화해서 만들어놨다. 그러므로 나중에 다른 서블릿컨테이너가 쓰고싶다면 new TomcatServletWebServerFactory(); 대신 new JettyServletWebServerFactory(); 을 쓰는 등 이 부분만 교체해 나머지 부분은 동일한 방식으로 사용할 수 있게 이렇게 만들어놓은 것. 스프링은 추상화를 좋아한다!

이렇게 웹서버 설정까지 했다. 그 전에 여기에 여러 가지 복합한 종류의 설정도 가능하다. 어쨌건 기본적으로 바로 사용 가능한 세팅이 Factory 안에 있기 때문에 처음엔 신경 안쓰고 넘어갈 것. 웹서버를 가져왔으니 아까 본 start 라는 메소드가 있는데 이걸 실행하면 Tomcat Servlet Container 가 동작한다.

@SpringBootApplication
public class HelloApplication {

  public static void main(String[] args) {
    ServletWebServerFactory serverFactory = new TomcatServletWebServerFactory();
	  WebServer webServer = serverFactory.getWebServer();
	  webServer.start();
  }
}

보면 Tomcat 웹 서버가 8080 포트에 ContextPath 가 지정되지 않았고 아무튼 떠있다는 메세지가 나왔다. 이제 8080 포트에 호출을 해보면 404 가 리턴되는 것을 확인할 수 있다. 이는 톰캣 서버까지 잘 떴고 서블릿 컨테이너가 우리가 만든 코드에 의해 시작되었음을 알 수 있다. 다음부터 여기에 서블릿을 추가해볼 예정.