사전 Maven
구현체

Maven

gabury1

Maven 은 자바 프로젝트의 빌드를 대신 돌려 주는 도구입니다. 컴파일과 테스트, 파일 묶기를 명령 한 줄로 끝냅니다. 무엇을 만들지는 프로젝트 안에 둔 설정 파일에 적습니다. 빌드가 어떤 순서로 도는지는 Maven 이 고정해 두었습니다.

쉽고 빠른 이해

Maven 은 빌드를 대신 돌려 주는 도구입니다. mvn package 한 줄이면 컴파일부터 테스트, 배포용 파일 묶기까지 끝납니다.

이게 없으면 사람이 컴파일러를 손으로 불러야 합니다. 쓸 라이브러리도 직접 내려받아 경로에 얹어야 합니다. 파일이 수백 장이 되면 사람이 따라갈 수 없습니다.

어떻게 도나:

  1. 설정 파일을 읽어 이 프로젝트가 무엇을 쓰고 무엇을 만드는지 알아냅니다
  2. 없는 라이브러리는 저장소에서 내려받아 자기 컴퓨터에 쌓아 둡니다
  3. 고정된 순서를 처음부터 훑으며 단계마다 할 일을 돌립니다

대가는 빌드에 적을 수 있는 것이 좁다는 점입니다. 설정 파일에는 할 일의 절차를 못 적습니다. 정해진 순서에서 벗어나는 빌드를 짜려면 도구를 확장하는 별도 부품을 써야 합니다.

상세

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 입니다. 이 셋이 좌표입니다.

라이브러리가 쌓여 있는 곳은 아티팩트 저장소입니다. 아티팩트 저장소는 빌드 결과물을 이름과 버전으로 보관해 두고 달라는 쪽에 내주는 서버입니다.

XML
<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 이 만든 결과물이 지나가는 다음 단계

아티팩트 · 지속적 통합 · 배포 · Nexus · Artifactory · 컨테이너 이미지

다른 이름: 메이븐 · Apache Maven · 아파치 메이븐