Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 |
Tags
- Ajax
- 사면초가
- DDD
- 공통규약
- springsecurity
- OOP
- 전전긍긍
- Transaction
- JPA
- 문제선택근거
- 단위테스트
- 커뮤니티서버
- MVC요청플로우
- 이벤트핸들러등록
- 로그백
- 클린아키텍처
- 이벤트핸들러this
- 디스크i/o
- TDD
- MVC
- model
- JDBC
- SEQUENCE
- string
- SpringLegacy
- AOP
- 공통기술
- index
- 설정세팅
- 냄새라도
Archives
- Today
- Total
개발이군고구마
build gradle의 상세 과정 본문
728x90
1. 전체 흐름

2. 1단계 : JVM — "Write Once, Run Anywhere"의 비밀

Java 코드는 **컴파일하면 .class 파일(바이트코드)**
이 바이트코드는 특정 OS의 언어가 아니라 JVM만 이해하는 중간 언어
서버에 JVM(Java가 설치된 것)만 있으면, 어디서든 같은 JAR 파일을 실행할 수 있는 이유
3. 2단계: Gradle이 하는 일

Gradle이 ./gradlew build 명령 하나로 이 4단계를 순서대로 자동 처리
특히 ④ 패키징 단계가 핵심인데, 여기서 만들어지는 것이 바로 "Fat JAR" 또는 "Executable JAR"
4. 3단계: JAR 파일 안에 뭐가 들어있나?
app.jar 내부 구조 (사실 zip 파일!)

JAR 파일의 핵심은 MANIFEST.MF.
이 안에 Main-Class: com.example.App이라고 적혀 있어서, JVM이 "어디서부터 시작해야 하는지"를 알 수 있음
java -jar app.jar = "JVM아, 이 JAR 열어서 MANIFEST 읽고 Main-Class 실행해"라는 뜻.
요약 :
- 소스코드 .java → Gradle이 javac로 컴파일 → 바이트코드 .class
- .class + 라이브러리 + 설정 → Gradle이 하나로 묶음 → app.jar
- app.jar → S3에 업로드 → 서버에서 다운로드
- 서버에서 java -jar app.jar → JVM이 시작 → MANIFEST 읽어서 main() 실행 → 서버 프로세스 시작!
5. MANIFEST.MF?
MANIFEST.MF는 JAR 파일의 "설명서 첫 페이지". 책으로 치면 "1장은 몇 페이지부터 시작합니다"라고 적힌 목차 같은 것.
Main-Class가 없으면 JVM 입장에서는 수백 개의 .class 파일 중 어디서 시작해야 할지 알 방법이 전혀 없음.
그래서 Main-Class가 없으면 java -jar가 아예 실행이 안 됨.

java -jar 실행 시 JVM이 MANIFEST.MF를 읽는 과정을 단계별로 설명하는 인터랙티브 설명
1단계: 명령어 입력
2단계: JAR 탐색
3단계: MANIFEST 읽기
4단계: main() 호출
5단계: 결과
터미널 입력
사용자가 명령어를 입력
$ java -jar app.jar
이 명령어는 사실 세 가지 정보를 JVM에 전달해요.
java → JVM을 시작해-jar → 이 JAR 파일을 실행 모드로 열어app.jar → 이 파일이야-jar 플래그가 핵심이에요. 이게 있어야 JVM이 "MANIFEST.MF를 읽어서 Main-Class를 찾아야겠다"고 결정해요.JVM 내부 동작
JAR를 열어 META-INF 폴더 탐색
app.jar (사실 zip 파일)
├── META-INF/
│ └── MANIFEST.MF ← JVM이 제일 먼저 여기 옴
├── com/
│ └── example/
│ └── App.class
└── BOOT-INF/
└── lib/ (라이브러리들)
├── META-INF/
│ └── MANIFEST.MF ← JVM이 제일 먼저 여기 옴
├── com/
│ └── example/
│ └── App.class
└── BOOT-INF/
└── lib/ (라이브러리들)
JAR는 실제로 zip 압축 파일이에요. JVM은
-jar 옵션을 보는 순간, 가장 먼저 META-INF/MANIFEST.MF 경로로 직행해요. 다른 파일은 아직 건드리지 않아요.MANIFEST.MF 읽기
Main-Class 항목을 찾아 읽음
Manifest-Version: 1.0
Main-Class: com.example.App ← 이것만 있으면 됨
Spring-Boot-Version: 3.2.0
Build-Jdk: 17.0.8
Main-Class: com.example.App ← 이것만 있으면 됨
Spring-Boot-Version: 3.2.0
Build-Jdk: 17.0.8
JVM은 이 파일을 한 줄씩 읽으면서
나머지 줄들(Spring-Boot-Version, Build-Jdk 등)은 참고 정보일 뿐, JVM 실행에는 영향을 주지 않아요.
Main-Class:로 시작하는 줄을 찾아요. 찾는 순간 com.example.App이라는 문자열을 메모리에 저장하고 다음 단계로 넘어가요.나머지 줄들(Spring-Boot-Version, Build-Jdk 등)은 참고 정보일 뿐, JVM 실행에는 영향을 주지 않아요.
클래스 로딩
App.class를 로드하고 main() 호출
// com/example/App.class 안에 이런 메서드가 반드시 있어야 함
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
JVM은
이 4개 키워드가 하나라도 다르면 실행 실패예요. JVM이 약속한 "진입점 계약"이거든요.
com.example.App 클래스를 JAR에서 꺼내 로드한 다음, 정확히 이 시그니처를 가진 메서드를 찾아요.public static void main(String[] args)이 4개 키워드가 하나라도 다르면 실행 실패예요. JVM이 약속한 "진입점 계약"이거든요.
성공 케이스
Main-Class가 있고 main()도 있을 때
. ____ _
/\\ / ___'_ __ _ _(_)
( ( )\___ | '_ | '_| |
\\/ ___)| |_)| | | |
' |____| .__|_| |_|
:: Spring Boot ::
Started App in 2.341 seconds
/\\ / ___'_ __ _ _(_)
( ( )\___ | '_ | '_| |
\\/ ___)| |_)| | | |
' |____| .__|_| |_|
:: Spring Boot ::
Started App in 2.341 seconds
서버가 포트를 열고 요청 대기 시작!
실패 케이스
Main-Class가 없을 때
no main manifest attribute,
in app.jar
in app.jar
해결법: build.gradle에
추가 후 재빌드
mainClass = 'com.example.App'추가 후 재빌드
← 이전 1 / 5 2 / 5 3 / 5 4 / 5 5 / 5
'SERVER > Java' 카테고리의 다른 글
| 응집도/결합도 분석으로 본 '인터페이스를 사용하는 이유' (0) | 2026.01.09 |
|---|---|
| 자바 I/O (2) - (문자) 파싱 구현체 만들기 (0) | 2026.01.07 |
| 자바 I/O (1) - 원리 (0) | 2025.12.29 |
| [자료구조] LIST 원리 (0) | 2025.12.26 |
| [자료구조] MAP 원리 (0) | 2025.12.19 |