본문 바로가기

백엔드 면접준비/Java

8.JAR

JAR 파일 실행 명령어

java -jar ossapp.jar

 

JAR 실행과정

1. JVM(Java Vitual Machine) 실행

  • java -jar ossapp.jar 명령어를 입력하면, JVM이 실행됨

2. JAR 파일 해석 & 압축 해제(Mainfest 파일 확인)

  • JVM은 JAR 내부의 META-INF/MANIFEST.MF에서 Main-Class를 확인하고, 애플리케이션의 시작업을 찾는다.
  • 일반 JAR : Main-Class에 지정된 main() 메서드를 실행
  • Spring Boot JAR : JarLauncher가 먼저 실행되고, Start-Class로 지정된 클래스를 찾아 실행

3. 클래스 로드 & 클래스 로더 동작 

  • JVM은 Main-Class의 main() 메서드를 실행하기 위해 ClassLoader를 사용하여 .class 파일을 메모리에 로드함
  • 일반 JAR : AppClassLoader가 Main-Class를 로드하고 실행함
  • Spring Boot JAR : LaunchedURLClassLoader가 Fat JAR(애플리케이션의 실행에 필요한 모든 클래스 및 의존 라이브러리를 하나의 JAR 파일에 포함) 내부의 라이브러리와 클래스를 동적으로 로드함

4. main() 메서드 실행

  • Spring Boot JAR의 경우, main() 메서드가 실행되면서 내장 웹 서버(Tomcat/Jetty)가 시작되거나 Spring Context가 초기화

5. 프로그램 실행 & 종료


일반 JAR vs Spring Boot JAR

  일반 Java JAR Spring Boot Jar(Fat JAR)
실행 명령어 java -jar ossapp.jar
(외부 라이브러리를 사용한다면 별도 지정 필요)
java -jar ossapp.jar
Main-Class com.example.MainApplication org.springframework.boot.loader.JarLauncher
의존성 관리 classpath로 관리 Fat JAR로 내부에 포함
내장 웹 서버 없음 Tomcat/Jetty 포함 가능
실행 방식 JVM이 직업 Main-Class 실행 JarLauncher가 Start-Class 실행

일반 JAR 예제

  • 프로젝트가 여러 개의 외부 라이브러리를 사용했더라도, 빌드 시 ossapp.jar 하나만 만들어짐
  • 의존성을 따로 지정해야함

JAR 빌드

javac -cp "libs/*" MainApplication.java
jar cf ossapp.jar com/example/MainApplication.class

실행

java -cp "libs/*:ossapp.jar" com.example/MainApplication

Spring Boot JAR(Fat JAR)

  • Spring Boot는 Fat JAR을 기본적으로 생성함
  • 실행에 필요한 Spring Boot 라이브러리, 애플리케이션 코드, 의존성, JAR 모두 포함됨
  • java -jar build/libs/springBootTest-0.0.1-SNAPSHOT.jar 한줄로 실행 가능

Fat JAR 빌드(Gradle)

./gradlew build

실행

java -jar build/libs/springBootTest-0.0.1-SNAPSHOT.jar --server.port:9911

Spring Boot Fat JAR 내부구조

  • BOOT-INF/lib/에 모든 라이브러리가 포함되므로, 추가적인 classpath 설정 없이 실행 가능
springBootTest-0.0.1-SNAPSHOT.jar
 ├── META-INF/
 ├── BOOT-INF/  <== Spring Boot의 실행 파일 영역
 │   ├── classes/  <== 애플리케이션의 클래스 파일
 │   ├── lib/  <== 모든 의존성 JAR 포함됨
 │   └── layers.idx (Spring Boot Layered JAR)
 ├── org/springframework/boot/loader/  <== Spring Boot의 실행 로더 (JarLauncher)
 └── META-INF/MANIFEST.MF  <== 실행할 `Start-Class` 지정

Fat JAR을 사용하는 이유

  • JAR 하나만 있으면 실행이 가능하므로 배포가 간편함
  • 추가 라이브러리 설치 없이 독립적인 실행 환경 제공
  • 따른 웹 서버를 설치하지 않아도 Spring Boot 내장 톰캣 지원

gradlew(Gradle Wrapper)

  • Gradle이 설치되어 있지 않아도 프로젝트에서 Gradle을 실행할 수 있도록 도와주는 스크립트 파일
  • 프로젝트 내부에 있는 특정 버전의 Gradle을 자동으로 다운로드하고 실행하는 역할
  Gradle Wrapper(gradlew) Gradle(gradle)
설치 필요 여부 별도 설치 필요 없음 시스템에 Gradle 설치 필요
버전 고정 가능 프로젝트 내에서 특정 Gradle 버전 유지 시스템에 설치된 버전 사용
실행 방식 ./gradlew [task] gradle [task]

(./gradlew)bootJar vs (./gradlew)build

  • 둘 다 JAR 파일을 생성하지만, 동작 방식이 다름

1. ./gradlew bootJar (Spring Boot 실행 가능한 JAR 생성)

  • Spring Boot에서 실행 가능한 Fat JAR을 생성하는 TASK
  • 내부적으로 의존성을 포함한 실행 가능한 JAR이 만들어짐

2. ./gradlew build (일반적인 빌드)

  • build TASK는 전체 프로젝트를 빌드하는 작업을 수행
  • bootJar를 포함해서, 필요하면 test도 실행하고 JAR을 생성
  • 즉, ./gradlew build 실행 시 내부적으로 bootJar도 실행됨

Gradle 기타설정..

ext가 Gradle파일 맨 위에 있으면 안되는 이유

  • Gradle 스크립트(build.gardle.kts 또는 build.gradle)은 다음과 같은 실행순서를 따른다.
    1. 플러그인(plugins{} 또는 apply plugin)이 먼저 로드
    2. 프로젝트 관련 속성(grop, version, repositories, dependencies)이 설정
    3. 빌드 테스크(bootJar, jar 등)가 설정
    4. 빌드 실행(gradlew build 등)
  • 그래서 ext 속성을 Gradle 파일의 최상단에 두면, 아직 프로젝트 객체가 로드되기 전에 선언되어 오류가 발생한다.
    -> ext 속성은 plugins {} 이후에 배치해야함
  • Groovy DSL에서 "(더블 쿼테이션)은 변수치환을 하고 '(싱클 쿼테이션)은 변수치환을 하지 않는다.

build.gradle 예제

ext {
	appName = 'ossapp'
	appVersion = '2.0.0'
}

bootJar {
	archiveBaseName = appName   // 기본 이름
	archiveVersion = appVersion    // 버전 (기본값: build.gradle의 version 속성)
	archiveClassifier = 'release' // 추가 라벨 (예: beta, release)
}

jar {
	archiveBaseName = "${appName}-lib"
	archiveVersion = appVersion
}

 

build 결과물

 

 

 

 

 

 

 

'백엔드 면접준비 > Java' 카테고리의 다른 글

객체지향  (0) 2025.03.19
JAVA 기본  (1) 2025.03.16
7. 동기,비동기, 블로킹, 논블록킹  (1) 2025.03.08
6. Garbage Collection(GC)  (1) 2025.03.07
4. Java Annotation  (0) 2025.03.07