SPRING/Spring Boot

[SpringBoot] 실행가능한 JAR

IT록흐 2023. 4. 27. 16:20
반응형

 

 

SpringBoot는 웹어플리케이션을 마치, JAVA 프로그램처럼 구동한다.

 

이전에는 방식이 달랐다.

 

 

 

개발자가 코드를 짜면 외장 웹서버 환경에서 동작 가능하도록 WAR형식으로 압축한 뒤, 웹서버에 배포해야만 했다. SpringBoot는 내장웹서버를 사용한다.  그래서 웹어플리케이션이 JAVA프로그램 같이 구동된다.

 

 

실행가능한 JAR

 

JAR 파일은 여러 JAVA클래스 파일이 배포가능하도록 하나로 묶은 파일이다. JAR가 Main클래스가 있어서 실제 프로그램으로 실행가능하다면 이를, 실행가능한 JAR 라 부른다.

 

package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {
	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}
}

 

 

SpringBoot에서 프로젝트를 하나 생성하면 main 메소드를 지닌 클래스가 존재한다. 그리고 이를 실행하면 localhost:8080에 웹서비스가 동작한다.  이전에는 소스를 배포하고 웹서버를 따로 실행했다. SpringBoot는 JAVA소스로 웹서버가 내장되어 있기에,  JAVA프로그램처럼 main 메소드로 동작하는 것이다. 그러므로 war는 필요없고 jar만 필요하다. 

 

그러나 실행가능한 JAR로 압축하는 과정에서 문제가 발생한다.

 

war는 jar를 포함하지만 jar는 jar를 포함하지 못한다. 

 

개발자가 직접 구현한 코드 외에도, 외부에서 가져온 jar도 있다. 내장톰캣도 하나의 외부jar이다. war는 특정한 구조가 있어 jar를 포함할 수 있지만 jar는 또 다른 jar를 포함시킬 수 있는 구조를 가지고 있지 않다.  이런 문제를 해결하기 위해, 이전에는 FatJar 방식으로 모든 jar를 class파일로 푼 뒤, 다시 하나의 jar로 만드는 방식을 사용했지만, jar간 경계가 사라지고 파일이름이 중복되는 문제가 발생하여 적합하지 않다.

 

그래서 SpringBoot는 마치 war처럼 특정한 구조를 지닌 SpringBoot만의 실행가능한 JAR 구조를 만들었다.

 

 

SpringBoot의 JAR

 

SpringBoot의 JAR 구조를 확인해보자. 우선 JAR파일을 생성해보자. ( MacOS 기준 )

 

1. JAR파일 생성하기

터미널에서 프로젝트 위치로 이동한다.

./gradlew build 명령어를 실행하여, build를 수행한다.

build 폴더 아래의 libs 폴더 아래에 jar파일이 생성되어 있음을 확인할 수 있다.

그럼 압축을 풀어보자.

 

2. JAR파일 압축풀기

 

명령어 : jar -xvf demo-0.0.1-SNAPSHOT.jar

압축을 풀면 위와 같은 구조가 나타난다. 

 

1) org

2) META-INF

3) BOOT-INF

 

 

org

~ /build/libs/org/springframework/boot/loader 로 이동하면 굉장히 다양한 클래스 파일을 확인할 수 있다.

SpringBoot가 동작하는데 필요한 파일들이다. 그중 JarLanuncher.class는 SpringBoot의 Main클래스를 실행시키는 클래스이다. 이는 META-INF 폴더의 설정파일에서 확인 가능하다.

 

META-INF 

META-INF 폴더에는 MANIFEST.MF 파일이 존재한다. 

 

Manifest-Version: 1.0 
Main-Class: org.springframework.boot.loader.JarLauncher      // main메소드를 실행하기 전, 전처리 클래스
Start-Class: com.example.demo.DemoApplication                     // 실행가능한 jar가 실행할 main메소드 위치
Spring-Boot-Version: 3.0.6
Spring-Boot-Classes: BOOT-INF/classes/                                    // 개발자가 구현한 코드 위치
Spring-Boot-Lib: BOOT-INF/lib/                                                     // 라이브러리 경로
Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx            // 외부라이브러리 모음
Spring-Boot-Layers-Index: BOOT-INF/layers.idx                         // 스프링부트 구조정보
Build-Jdk-Spec: 17
Implementation-Title: demo
Implementation-Version: 0.0.1-SNAPSHOT

 

MANIFEST.MF 파일은 SpringBoot가 실행되기 전 필요한 설정정보를 갖고 있다.

 

DemoApplication에 main메소드가 있지만 실제로는 JarLauncher 클래스가 먼저 실행되어 전처리 과정을 마친 뒤, DemoApplication이 실행된다. 이외에도 jar안에 jar가 포함될 수 있도록 외부라이브러리 경로를 따로 지정한 설정이 있다.

 

BOOT-INF

WAR에서는 WEB-INF에 해당하는 영역이다.

 

BOOT-INF 아래 위치한 폴더 및 파일은 MANIFEST.MF에서 정의한 역할을 수행한다.

 

Spring-Boot-Classes: BOOT-INF/classes/                                    // 개발자가 구현한 코드 위치
Spring-Boot-Lib: BOOT-INF/lib/                                                     // 라이브러리 경로
Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx            // 외부라이브러리 모음
Spring-Boot-Layers-Index: BOOT-INF/layers.idx                         // 스프링부트 구조정보

jar 폴더 안에는 jar가 존재할 수 없지만 SpringBoot만의 특별한 jar에서는 lib 폴더 아래에 jar파일이 존재한다. 

 

 


 

정리하면,

 

웹 서비스는 복잡하고 다양한 라이브러리가 필요하므로 WAR 구조가 적합했다. WAR안에는 여러 JAR를 포함할 수 있기 때문이다. 그러나 WAR는 외부에 서버가 존재해야 한다.

 

웹서비스를 JAVA프로그램처럼 구동하려는 SpringBoot의 철학을 구현하려면 톰캣은 JAVA소스로 내장되어야 한다. 그러면 한 가지 문제가 있다. 내장톰캣 JAR와 개발자가 구현한 JAR가 하나의 JAR로 묶이지 못한다는 것이다. 그래서 SpringBoot는 SpringBoot만의 독특한 구조의 실행가능한 JAR를 만들어 냈다.

 

이로써 main메소드로 실행가능한 웹서비스가 탄생하게 되었다. 

 

 

 

반응형