Dev./Spring-Boot
Spring Boot는 왜 jar 파일로 실행 가능할까
hotamul
2023. 9. 2. 23:14
이전 포스트(Spring Boot가 뭔데?)에서 Spring Boot가 어떻게 시작되었고 어떤 기술인지 간단하게 살펴보았다. 이번에는 Spring Boot가 어떻게 독립 실행 될 수 있는지 알아보자.
Standalone executable jar
처음 Spring Boot 프로젝트를 생성하고 jar
파일로 빌드한 뒤 실행하면 아래와 같이 Spring 애플리케이션이 실행되는 것을 확인할 수 있다.
gradle을 빌드 도구로 사용할 경우 ./gradlew bootJar 명령을 실행하면 build/libs 아래에 jar 파일이 생성된다.
JAR: Java Archive, Java 애플리케이션이 동작할 수 있도록한 압축 파일이며 java runtime environment(jre)만 있어도 실행 가능하다.
$ java -jar build/libs/helloboot-0.0.1-SNAPSHOT.jar
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.7.15)
2023-09-02 22:35:33.744 INFO 3404 --- [ main] h.helloboot.HellobootApplication : Starting Hel
lobootApplication using Java 11.0.20 on DESKTOP-K4DIK6U with PID 3404 (C:\Users\J.H.Park\myworkspace\helloboot\b
uild\libs\helloboot-0.0.1-SNAPSHOT.jar started by J.H.Park in C:\Users\J.H.Park\myworkspace\helloboot)
[...]
별도의 웹서버, 웹 컨테이너 없이 jar 파일로 실행될 수 있는 이유는 Spring Boot가 기본적으로 대표적인 Servlet Container인 Tomcat을 포함하고 있기 때문이다.
$ ./gradlew dependencies --configuration compileClasspath
[...]
------------------------------------------------------------
Root project 'helloboot'
------------------------------------------------------------
compileClasspath - Compile classpath for source set 'main'.
\--- org.springframework.boot:spring-boot-starter-web -> 2.7.15
+--- org.springframework.boot:spring-boot-starter-tomcat:2.7.15
| +--- jakarta.annotation:jakarta.annotation-api:1.3.5
| +--- org.apache.tomcat.embed:tomcat-embed-core:9.0.79
| +--- org.apache.tomcat.embed:tomcat-embed-el:9.0.79
| \--- org.apache.tomcat.embed:tomcat-embed-websocket:9.0.79
| \--- org.apache.tomcat.embed:tomcat-embed-core:9.0.79
[...]
그러면 아래와 같은 프로젝트 초기 코드를 제거하고 직접 내장 Tomcat 서버를 실행하는 코드를 작성해보자.
[...]
@SpringBootApplication
public class HellobootApplication {
public static void main(String[] args) {
SpringApplication.run(HellobootApplication.class, args);
}
}
Naive standalone executable Tomcat Server
TomcatServletWebServerFactory.getWebServer
메소드를 이용해서 쉽게 Tomcat 서버 인스턴스를 생성할 수 있다.getWebServer
메소드는 ServletContextInitializer
인터페이스를 구현체를 전달받아야 하는데 이는 lambda 표현식으로 쉽게 표현할 수 있다. (WebServer getWebServer(ServletContextInitializer... initializers)
)
아래 코드는 이름을 query parameter에 담아 요청하면 "Hello [이름]"
으로 전달해주는 로직이 담겨있다.
[...]
public class HellobootApplication {
public static void main(String[] args) {
ServletWebServerFactory serverFactory = new TomcatServletWebServerFactory();
WebServer webServer = serverFactory.getWebServer(servletContext -> {
servletContext.addServlet("hello", new HttpServlet() {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = req.getParameter("name");
resp.setStatus(HttpStatus.OK.value());
resp.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE);
resp.getWriter().println("Hello " + name);
}
}).addMapping("/hello");
});
webServer.start();
}
}
애플리케이션을 구동하고 curl
로 정상적으로 응답이 return 되는지 확인해봤다.
$ curl -v "http://localhost:8080/hello?name=Spring"
* Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /hello?name=Spring HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.79.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200
< Content-Type: text/plain;charset=ISO-8859-1
< Content-Length: 14
< Date: Sat, 02 Sep 2023 14:08:05 GMT
<
Hello Spring
* Connection #0 to host localhost left intact
👍