[SpringBoot] Spring 에서 내장 웹 서버의 이해와 Servelt / ssl 인증

2020. 5. 3. 22:01개발/Spring

📌 [Spring] Spring 에서 내장 웹 서버 이해

먼저 서블릿이 뭔지 알아보도록 하겠다.

🙄🙄 Servelt 이란?

자바 서블릿(Java Servlet)은 자바를 사용하여 웹페이지를 동적으로 생성하는 서버측 프로그램 혹은 그 사양을 말하며, 흔히 "서블릿"이라 불린다. 자바 서블릿은 웹 서버의 성능을 향상하기 위해 사용되는 자바 클래스의 일종이다. 서블릿은 JSP와 비슷한 점이 있지만, JSP가 HTML 문서 안에 Java 코드를 포함하고 있는 반면, 서블릿은 자바 코드 안에 HTML을 포함하고 있다는 차이점이 있다. - 위키백과

한마디로 자바를 사용해서 웹페이지를 동적으로 생성하는 서버측의 클래스. 라고 생각이 든다.

이렇게만 보면 이해가 잘 안가니 이분이 정리해두신 정리를 참고해서 이해해보자

서블릿의 동작은 다음과 같이 이루어진다

  1. 사용자가 URL을 클릭하면 HTTP Request를 서블릿 컨테이너로 전송한다
  2. HTTP Request를 전달받은 서블릿 컨테이너는 HttpServletRequest, HttpServletResponse 두 객체를 생성한다.
  3. web.xml은 사용자가 요청한 URL을 분석하여 어느 서블릿에 대해 요청을 한 것인지 찾는다
  4. 해당 서블릿에서 service 메소드를 호출한 후 클라이언트의 요청종류 (GET, POST)에 따라 doGet 혹은 doPost를 호출한다.
  5. doGet, doPost 메소드는 동적 페이지를 생성한 후 HttpServletResponse 객체에 응답을 보낸다.
  6. 응답이 끝나면 HttpServletRequest, HttpServletResponse 두 객체를 소멸시킨다

위 과정은 우리가 Server로 request를 보내고 response를 받는 과정이다. 우리가 Spring에서, 혹은 다른 프레임 워크에서 사용하는 과정과 거의 흡사하지만, 조금 다르다. 4번 을 보면,

해당 서블릿에서 service 메소드를 호출한 후 클라이언트의 요청종류 (GET, POST)에 따라 doGet 혹은 doPost를 호출한다.

라고 되어 있는데 우리는 @Getmapping @Postmapping을 통해 이를 간편하게 수행하고 있지 않은가? 심지어 URL도 간편하게 지정해줄수 있다. 따라서 우리가 지정하는 일련의 과정을 Spring 내부에서 서블릿으로 생성해서 동작한다. 라고 생각할 수 있다. 이렇게 동작하는 서블릿들을 모아놓은 공간을 Servelt Container(서블릿 컨테이너) 라고 하며 Servelt Container중 하나로는 Tomcat을 볼 수 있다.

🥕🥕 따라서 WAS(Web Application Server)는 이런 일련의 과정들을 Servelt 으로 변환시켜주고 변환시킨 Servelt들을 관리하는 Servelt Container라고 볼 수 있다.

다음은 SpringBoot 내장 웹 서버 에 대해서 알아보자.

개념은 위와 똑같다. Tomcat을 사용하는것도 같다. 그럼 어떻게 알고 Tomcat을 불러오는걸까?

그건 저번장에서 했던 AutoConfigure 와 관련이 있다.

spring.factories에 가보면 ServletWebServerFactoryAutoConfiguration 가 있다. 이 클래스로 가보면

@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
        ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
        ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
        ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
    ...
}

위와 같이 import가 되어 있다. 여기서 웹 서버를 생성한다.

spring.factories 를 보면 DispatcherServeltServletWebServerFactoryAutoConfiguration 는 따로 떨어져 있는데, 이는 Servelt 컨테이너는 우리가 해주는 설정에 따라서 변경될 수 있지만 서블렛은 변경되지 않기 때문에 서로 떨어져 있다. DispatcherServelt 은 서블렛들과 서블렛 컨테이너를 연결시켜 주는 작업을 해준다.


📒 그럼 다른 웹 서버들로는 어떻게 실행 시킬까?

  1. 먼저 spring-boot-start 안에 있는 tomcat의존성을 빼주어야 한다. (maven에서는 exclusion 사용)
  2. 내가 원하는 웹 서버의 의존성을 추가시켜 준다.

📒 SSL 을 적용시켜서 웹서버 띄우기.

SSL 암호키를 생성해서 서버에 적용시키면, https 요청 이외에는 받을 수 없게 된다.

SSL에 관한 자세한 설명은 생활코딩 을 참고하자.

  1. keytool -genkey -alias spring -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 4000 이런식으로 key를 생성한다.

  2. #application.properties 
    server.ssl.key-store=keystore.p12
    server.ssl.key-store-type=PKCS12
    server.ssl.key-store-password=123456
    server.ssl.key-alias=spring
  3. 이제 해당 인증서 없이 https로 접속하려고 하면 안전하지 않은 페이지 라고 나올텐데, 이는 브라우저가 해당 사이트의 public key 를 몰라서 그런것이다. (대부분의 웹사이트는 가지고 있음)

Connector가 하나이기 때문에 해당 커넥터에 인증서를 입히면 http 요청을 받을 수 없게된다. 하지만 https와 http를 같이 받을 방법이 있긴 하다. 바로 Connector를 하나 더 만들어 주는 것.

    @Bean
    public ServletWebServerFactory serverFactory(){
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
        tomcat.addAdditionalTomcatConnectors(createStandardConnector());
        return tomcat;
    }

    private Connector createStandardConnector() {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setPort(8080);
        return connector;
    }

이와 같이 Connector를 하나 더 만들어주면 8080 포트로 접근했을때는 http를 받을 수 있다. (포트가 겹치면 안되니 application.properties에서 server.port=8443으로 바꾸어 https 요청 포트를 바꾸어 주도록 하자)


이제 http가 아닌 http2로 바꾸어서 진행해보자. http2는 2015년도에 나왔는데 자세한 설명은 다른 분 블로그 를 참고 하도록 하자. HTTP2는 기본적으로 SSL이 필요하다. 따라서 SSL을 먼저 적용한 다음 바꾸도록 하자.

사용하는 서블릿 컨테이너 마다 설정법이 다르다. Spring document 여기를 참고하면 서블릿 컨테이너 마다 HTTP2를 설정하는 방법이 나와있다. (예를들어 Undertow 같은 경우는 server.http2.enabled = true로 설정해 주기만 하면 된다.)