[Spring Boot] 부트와 내장 WAS
웹 서버와 웹 애플리케이션 서버에 대해 제대로 알고 넘어가자.
웹 서버는 HTTP 프로토콜로 들어오는 클라이언트의 요청을 받아 처리하는 역할을 수행한다. (Apache, Nginx)
웹 애플리케이션 서버 (WAS) 도 클라이언트의 요청을 받아 동적인 컨텐츠를 제공한다. (Tomcat, Express, Django..)
웹 서버는 페이지를 렌더링 할 때 필요한 정적인 컨텐츠와 로드밸런싱, SSL 암호화 등을 빠르게 제공하고 웹 애플리케이션 서버는 동적인 컨텐츠를 제공한다.
스프링 애플리케이션은 WAS 위에서 실행되고, 웹 서버를 앞에 두고 웹 서버를 통해 클라이언트의 요청을 전달받고 요청을 처리하는 방식을 자주 사용한다.
클라이언트가 웹 서버에 HTTP 요청을 보내면 웹 서버가 정적 컨텐츠 요청인지 동적 컨텐츠 요청인지 판단하고 필요에 따라 WAS로 요청을 전달한다.
Tomcat은 웹 애플리케이션 서버이긴 한데 정적인 컨텐츠를 제공하는 웹 서버의 역할도 함께 수행할 수 있다. (웹 서버보다는 성능이 떨어진다)
백엔드를 스프링으로 개발하고 프론트엔드를 Vue로 개발했다고 하자.
스프링은 WAS 위에서 실행되고 Vue는 웹 서버에서 호스팅된다. (프론트엔드는 WAS를 포함하지 않는다)
클라이언트의 요청은 프론트엔드의 웹 서버로 연결되고, api 요청이 필요한 경우 프론트엔드 웹 서버는 백엔드에게 요청한다.
스프링으로 개발한 백엔드 애플리케이션이 Apache 웹 서버를 포함하고 있다면 웹 서버가 요청을 받고 Tomcat에게 요청을 넘겨주고, 포함하지 않는 경우 WAS가 바로 요청을 받아서 처리한다.
처리 결과는 프론트엔드에게 전달되고 결과를 바탕으로 화면을 렌더링한다.
스프링 부트 애플리케이션에는 main 메서드가 있고, 실행 시 내장된 Tomcat이 실행된다.
지금까지는 Tomcat을 따로 설치하고 작성한 Java 코드를 WAR 파일로 패키징해 Tomcat에 WAR파일을 배포하는 방식으로 애플리케이션을 실행했지만, 이제는 Java 코드를 컴파일하면 얻을 수 있는 JAR 파일 내부에 WAS가 포함돼 쉽게 애플리케이션을 실행할 수 있게 됐다.
내장 Tomcat은 Tomcat을 라이브러리로 포함하고 Java코드로 직접 실행함을 의미한다.
public class EmbededTomcatServletMain {
public static void main(String[] args) throws LifecycleException {
System.out.println("main....");
// Tomcat
Tomcat tomcat = new Tomcat();
Connector connector = new Connector();
connector.setPort(8080);
tomcat.setConnector(connector);
// Servlet
Context context = tomcat.addContext("", "/");
tomcat.addServlet("", "helloServlet", new HelloServlet()); // 서블릿 이름
context.addServletMappingDecoded("/hello-servlet", "helloServlet");
tomcat.start();
}
}
내장 Tomcat으로 클라이언트의 요청을 처리하는 예시이다.
Tomcat이 실행될 포트번호를 등록하고 요청을 처리할 서블릿을 등록한다.
스프링 컨테이너도 함께 등록해서 내장 Tomcat에 배포할 수 있다.
JAR 파일 실행 시 실행될 메인 메서드는 META-INF/MANIFEST.MF 파일에 지정해 줘야 한다. (pom 또는 gradle로 설정하자)
애플리케이션을 JAR로 패키징하면 개발자가 작성한 소스코드만 패키징되고 추가되는 라이브러리들은 패키징되지 않는다.
WAR는 WAS 위에서만 실행할 수 있는 파일으로 라이브러리 역할을 하는 JAR를 모두 포함하지만 JAR는 내부에 JAR를 포함하지 못한다.
대신 클래스들은 포함할 수 있다.
이 부분을 사용해 jar 내부에 라이브러리들을 클래스로 포함하는 방식을 사용할 수 있지만, jar 파일이 너무 무거워지고 파일명 중복이 발생했을 때 해결할 수 없다는 단점이 있다. (Fat Jar)
스프링 부트는 JAR 내부에 JAR를 포함할 수 있는 특별한 구조인 Excutable Jar를 만들어서 해당 문제를 깔끔하게 해결한다.
Excutable Jar는 스프링 부트에서 새롭게 정의한 구조이고, 기존 JAR의 규격과 비슷하게 정의된다.
META-INF/MANIFEST.MF 에 실행할 메인 메서드를 지정해주고
BOOT-INF/classes 에 작성한 소스코드와 리소스를 저장하며 (WAR의 WEB-INF와 유사하다)
BOOT-INF/lib 에 JAR 형태로 저장된다.
여기까지는 특별한 점이 없지만, MANIFEST.MF에서 메인 클래스는 JarLauncher로 지정되어 있어 지정한 메인 메서드 대신 실행된다.
JarLauncher가 JAR 내부에 있는 JAR 파일들을 읽어들이고 Start-Class 에 지정된 메인 메서드를 호출한다.
내부에 있는 JAR 파일을 읽기 위해 Layer를 한 계층 더 추가했다고 생각하면 된다.
@SpringBootApplication
public class BootApplication
{
public static void main(String[] args) {
SpringApplication.run(BootApplication.class, args);
}
}
스프링 부트를 사용할 때는 main 메서드에서 run 메서드만 호출하는 방식으로 설계됐다.
메인 설정 정보를 메서드의 매개변수로 넘겨주는데, @SpringBootApplication 애너테이션은 @ComponentScan 애너테이션을 포함하고 있어 빈들을 자동으로 등록할 수 있어 @SpringBootApplication 애너테이션이 붙은 클래스를 메인 설정 정보로 사용할 수 있다.
run 메서드를 실행하게 되면 내부적으로 스프링 컨테이너와 내장 WAS를 생성한다.
스프링 컨테이너와 WAS를 생성하는 작업은 이전에 진행한 방식과 비슷하게 진행된다.
IntelliJ, Eclipse 같은 IDE는 외부 라이브러리를 쉽게 가져다 사용할 수 있어 스프링 부트 애플리케이션을 실행하면 바로 메인 메서드를 실행하지만, 다른 환경에서 Jar로 패키징된 파일을 실행할 때는 JarLauncher가 메인 메서드보다 먼저 실행됨을 기억하자.
스프링 부트는 내장 Tomcat 관련 예외처리 및 다양한 기능을 자동화해서 제공한다.
관련 내용을 깊게 공부하지 말고 원리만 대략적으로 알고 넘어가자. (적당한 추상화는 필요하다!!!)
'Spring > Spring Boot' 카테고리의 다른 글
[Spring Boot] 외부 설정 (0) | 2023.05.28 |
---|---|
[Spring Boot] 자동 구성 (0) | 2023.05.26 |
[Spring Boot] 라이브러리의 선택과 버전 관리 (0) | 2023.05.23 |
[Spring Boot] 스프링과 웹 서버 (0) | 2023.05.21 |
[Spring Boot] 스프링 부트의 도입 (0) | 2023.05.14 |
댓글
이 글 공유하기
다른 글
-
[Spring Boot] 자동 구성
[Spring Boot] 자동 구성
2023.05.26 -
[Spring Boot] 라이브러리의 선택과 버전 관리
[Spring Boot] 라이브러리의 선택과 버전 관리
2023.05.23 -
[Spring Boot] 스프링과 웹 서버
[Spring Boot] 스프링과 웹 서버
2023.05.21 -
[Spring Boot] 스프링 부트의 도입
[Spring Boot] 스프링 부트의 도입
2023.05.14