Maven
Maven 은 자바 프로젝트의 빌드를 대신 돌려 주는 도구입니다. 컴파일과 테스트, 파일 묶기를 명령 한 줄로 끝냅니다. 무엇을 만들지는 프로젝트 안에 둔 설정 파일에 적습니다. 빌드가 어떤 순서로 도는지는 Maven 이 고정해 두었습니다.
쉽고 빠른 이해
Maven 은 빌드를 대신 돌려 주는 도구입니다. mvn package 한 줄이면 컴파일부터 테스트,
배포용 파일 묶기까지 끝납니다.
이게 없으면 사람이 컴파일러를 손으로 불러야 합니다. 쓸 라이브러리도 직접 내려받아 경로에 얹어야 합니다. 파일이 수백 장이 되면 사람이 따라갈 수 없습니다.
어떻게 도나:
- 설정 파일을 읽어 이 프로젝트가 무엇을 쓰고 무엇을 만드는지 알아냅니다
- 없는 라이브러리는 저장소에서 내려받아 자기 컴퓨터에 쌓아 둡니다
- 고정된 순서를 처음부터 훑으며 단계마다 할 일을 돌립니다
대가는 빌드에 적을 수 있는 것이 좁다는 점입니다. 설정 파일에는 할 일의 절차를 못 적습니다. 정해진 순서에서 벗어나는 빌드를 짜려면 도구를 확장하는 별도 부품을 써야 합니다.
상세
Maven 은 빌드 도구입니다. 빌드 도구는 소스 코드를 결과물로 바꿔 주는 프로그램입니다. 그 결과물은 실행하거나 배포할 수 있습니다. 바꾸는 과정에는 컴파일, 테스트, 파일 묶기, 저장소에 올리기가 들어갑니다.
자바 프로젝트 하나를 손으로 빌드한다고 해 봅니다. 쓸 라이브러리를 웹에서 찾아 내려받아야 합니다. 소스는 javac 로 컴파일합니다. javac 는 자바 소스를 클래스 파일로 바꾸는 자바 공식 컴파일러입니다.
그다음 테스트를 돌리고, 나온 클래스 파일을 JAR(Java ARchive, 자바 아카이브) 파일 하나로 묶습니다. JAR 은 클래스 파일 여럿을 한 파일로 묶은 것입니다. Maven 은 이 일을 전부 맡습니다.
Maven 자신도 JVM(Java Virtual Machine, 자바 가상 머신) 위에서 도는 프로그램입니다. 그래서 설치하려면 자바가 먼저 있어야 합니다.
프로젝트를 적는 파일 하나
Maven 은 프로젝트 하나를 파일 하나로 봅니다. 앞에서 말한 설정 파일이 이 파일입니다.
그 파일 이름은 pom.xml 입니다. POM(Project Object Model, 프로젝트 객체 모델)이라고
부릅니다.
POM 에는 이 프로젝트의 이름, 쓰는 라이브러리 목록, 빌드에 얹을 부품이 들어갑니다. 형식은 XML(eXtensible Markup Language, 확장 가능한 마크업 언어)입니다. XML 은 여는 태그와 닫는 태그로 값을 감싸 적는 표기법입니다.
POM 은 설정 목록입니다. 절차를 적는 곳이 아닙니다. 조건문도 반복문도 없고, 있는 것은 「무엇을 쓴다」와 「무엇을 만든다」뿐입니다. 이 성질이 뒤의 「적을 수 있는 것을 좁힌 선택」의 뿌리입니다.
고정된 빌드 순서
Maven 의 빌드는 빌드 수명 주기를 따릅니다. 빌드 수명 주기는 도구가 고정해 둔 단계의 줄입니다. 단계 하나가 페이즈입니다.
페이즈 이름은 앞에서부터 validate · compile · test · package · verify ·
install · deploy 일곱입니다. 설정 검사로 시작해 컴파일과 테스트를 지나 파일로 묶고,
마지막에 저장소로 올라갑니다.
페이즈 자신은 빈 칸입니다. 실제 일은 플러그인이 합니다. 플러그인은 페이즈에 붙어 그때
할 일을 하나 맡는 부품입니다. 컴파일 플러그인이 compile 에, 테스트 플러그인이 test 에
붙어 있습니다.
flowchart TD
subgraph PH["페이즈 · 순서가 고정된 빈 칸"]
direction TB
A["validate"] --> B["compile"] --> C["test"] --> D["package"] --> E["나머지 세 페이즈"]
end
subgraph PL["플러그인 · 칸에 붙어 일을 한다"]
P1["컴파일 플러그인"]
P2["테스트 플러그인"]
end
B -.-> P1
C -.-> P2
새 동작을 넣고 싶으면 원하는 페이즈에 플러그인을 하나 더 붙입니다. 그림에서 아무것도 안 매달린 페이즈가 그런 빈 칸입니다.
이 줄은 한 방향입니다. 되돌아가는 화살표가 없습니다.
부르는 법은 따로 정해져 있습니다. 어느 페이즈를 부르면 그 앞의 페이즈가 전부 먼저 돕니다.
테스트만 돌리려고 mvn test 를 불러도 검사와 컴파일이 같이 돌아갑니다.
mvn package # 배포용 파일 하나가 나온다
mvn test # compile 까지 같이 돈다
좌표로 라이브러리를 찾는다
쓰려는 라이브러리는 이름 대신 세 값의 묶음으로 가리킵니다. 만든 조직을 가리키는
groupId, 물건 이름인 artifactId, 그리고 version 입니다. 이 셋이 좌표입니다.
라이브러리가 쌓여 있는 곳은 아티팩트 저장소입니다. 아티팩트 저장소는 빌드 결과물을 이름과 버전으로 보관해 두고 달라는 쪽에 내주는 서버입니다.
<dependency>
<groupId>org.example</groupId>
<artifactId>my-lib</artifactId>
<version>1.2.3</version>
</dependency>
방금 본 세 줄이 그 저장소 안의 파일 하나를 가리킵니다. 좌표가 곧 저장소 안의 경로라서 그렇습니다.
이름만 적는 방식과는 여기서 갈립니다. 같은 이름의 라이브러리를 다른 조직이 내놓아도
groupId 가 달라 섞이지 않습니다.
라이브러리를 찾는 곳은 두 군데입니다. 먼저 자기 컴퓨터 안의 로컬 저장소를 봅니다. 거기 없으면 Maven Central 같은 공용 저장소에서 내려받고, 받은 것을 로컬 저장소에 남깁니다. 다음 빌드부터는 다시 안 받습니다.
flowchart TD
Q["좌표"] --> R{"로컬 저장소에 있나"}
R -->|"있다 · 다음 빌드부터는 늘 이 길"| U["그대로 쓴다"]
R -->|"없다"| V["Maven Central 에서 내려받는다"]
V --> W["로컬 저장소에 남긴다"]
W --> U
받아 온 라이브러리가 또 다른 라이브러리를 쓰고 있으면 그것도 같이 받습니다. 이렇게 딸려 오는 것을 전이 의존성이라고 부릅니다. 이것이 POM 에 하나만 적고도 라이브러리 수십 개를 받게 되는 까닭입니다.
flowchart TD
subgraph L1["POM 에 적은 것"]
T1["org.example:my-lib:1.2.3"]
end
subgraph L2["딸려 오는 것 · 전이 의존성"]
T2["org.a:lib-a:2.0"]
T3["org.b:lib-b:1.5"]
end
subgraph L3["그 아래로 또 딸려 오는 것"]
T4["org.c:lib-c:3.1"]
T5["나머지"]
end
T1 --> T2
T1 --> T3
T2 --> T4
T3 --> T5
정해진 디렉터리 배치
Maven 은 소스가 어디 있는지 묻지 않습니다. 있어야 할 곳이 이미 정해져 있습니다. 프로젝트 루트 아래 소스와 결과물이 이렇게 갈립니다.
flowchart TD
Z["프로젝트 루트"] --> Z1["src"]
Z --> Z2["target/ · 빌드가 만들어 낸 결과물"]
Z1 --> Z3["main/java · 실제로 배포되는 소스"]
Z1 --> Z4["test/java · 테스트 소스"]
이 배치를 따르면 POM 에 경로를 한 줄도 안 적습니다. 따르지 않으면 그때 적습니다. 정해 둔 쪽을 기본으로 삼고 어긋날 때만 적게 하는 이 방식을 설정보다 관례라고 부릅니다.
덕분에 처음 여는 프로젝트라도 어디에 무엇이 있는지 아는 상태로 시작합니다. 남의 저장소를
받아 와서 mvn package 한 줄을 치면 대개 빌드가 됩니다.
적을 수 있는 것을 좁힌 선택
Maven 은 빌드 파일에 절차를 적는 길을 일부러 막았습니다. POM 은 설정이라 「이럴 때는 이렇게 하라」를 못 적습니다. 순서를 뒤집거나 페이즈 하나를 통째로 건너뛰는 빌드도 어렵습니다.
포기한 대신 얻은 것이 모양의 균일함입니다. 어느 프로젝트를 열어도 POM 의 생김새가 비슷하고, 빌드가 도는 순서도 같습니다. 남이 짠 빌드를 읽을 때 코드를 따라갈 일이 없습니다.
Gradle 이 반대쪽을 골랐습니다. 빌드 파일이 코드라 무엇이든 적을 수 있고, 그만큼 사람마다 다르게 짭니다. 같은 저장소에서 같은 좌표로 라이브러리를 받는 것은 둘이 같습니다. 갈리는 곳은 빌드를 적는 방식 하나입니다.
고르는 기준도 여기서 나옵니다. 여러 팀의 빌드가 다 같은 모양이기를 바라면 Maven 쪽입니다. 빌드 안에서 조건을 따지고 단계를 새로 짜야 하면 Gradle 쪽입니다.
관련 항목
Maven 과 같은 역할을 두고 겨루는 빌드 도구
Gradle · Ant · sbt · Bazel · make · 빌드 도구
Maven 이 빌드하는 자바 프로그램의 구성 요소
Java · JVM · JDK · javac · 클래스 파일 · JAR · WAR · 클래스패스
Maven 빌드를 이루는 구성 요소
POM · XML · 빌드 수명 주기 · 플러그인 · 멀티 모듈 빌드 · 빌드 프로파일 · 설정보다 관례 · Maven 래퍼
Maven 이 라이브러리를 받아 오는 경로와 개념
의존성 · 전이 의존성 · 의존성 충돌 · 의존성 범위 · 로컬 저장소 · Maven Central · 아티팩트 저장소 · 시맨틱 버저닝
Maven 이 만든 결과물이 지나가는 다음 단계
다른 이름: 메이븐 · Apache Maven · 아파치 메이븐