[ 유용한 프로그램 ]

메이븐(Maven) 시작하기 (1/3) [펌]

SojuMan 2010. 7. 8. 16:04

메이븐으로 자바 프로젝트를 관리해 보자.

이전부터 자바 프로젝트를 시작할 때 제일 먼저하는 것은 이클립스를 띄우고, 자바 프로젝트를 만들고 라이브러리들을 lib 폴더에 추가하는 것이었다. 그런데 비슷비슷한 라이브러리들을 똑같이 사용하는 자바 프로젝트를 여러 개 만들다보면 비슷한 노가다를 계속해야 했다. 그러다가 조금 더 발전한 것이 여러 프로젝트에서 공통으로 사용하는 라이브러리 프로젝트를 만들어서 참조하게 한 것이다. 조금 편해졌지만 그래도 각 프로젝트마다 클래스패스를 잡아주는 것은 고역이었다.

그러다 메이븐이라는 것을 알게 되었다. 메이븐에서 라이브러리 혹은 프로젝트 의존 관계(Dependency)를 설정하는 것은 매우 간단하다. 설정 파일에 그 의존 관계를 선언하기만 하면 된다. 이클립스와의 연동도 가능하다. 메이븐에서 이클립스 프로젝트를 만들 수도 있고, 이클립스에서 메이븐 플러그인을 설치하여 메이븐 프로젝트를 만들 수도 있다.

메이븐은 사실 의존 관계 관리 도구라기보다는 프로젝트 관리 도구이다. 메이븐은 빌드 생명주기(Build Lifecycle)에 따라 프로젝트 표준을 제공하고 의존 관계를 관리하고 플러그인이 제공하는 부가 기능을 사용할 수 있게 하는 도구이다. 더 자세한 것은 메이븐 홈페이지나 Sonatype에서 공개한 메이븐 책(Maven: The Definitive Guide)를 참조하길 바란다. 메이븐 책은 무료로 다운로드 받을 수 있고, 영어임에도 불구하고 매우 쉽게 쓰여져 읽는 데 큰 어려움은 없다. Thanks, Sonatype. 메이븐 책을 3장까지만 읽어보면 감을 잡을 것이다. 사실 메이븐 책 3장까지 봤으면 이 포스트는 볼 필요도 없다. ㅎ_ㅎ (그래도 이건 한글이다. +_+)

일단 따라해보자.

애초에 라이브러리 관리를 더 편하게 하기 위해 메이븐을 사용하려고 했던 것이니 다른 라이브러리를 사용하는 프로젝트를 만들어 보자. 단위 테스트를 위한 JUnit 라이브러리와 자바 API를 보완하는 여러 기능들을 제공하는 Commons Lang 라이브러리 정도만 사용해 보자.

1. 메이븐을 설치한다.

메이븐 홈페이지에서 메이븐을 다운로드하고 적당한 폴더에 압축을 푼 뒤, 메이븐 폴더 내 bin 폴더를 PATH에 추가해준다. mvn --help 명령어를 쳤을 때 사용법이 제대로 나온다면 다음을 진행할 수 있다. mvn은 메이븐을 실행하는 명령어이다.

2. 메이븐 프로젝트를 만든다.

작업할 폴더에서 다음 명령어를 실행한다. 도중에 옵션을 물어보기도 하는데 그냥 엔터를 쳐서 기본값으로 넘어갈 수 있다.

mvn archetype:generate -DgroupId=net.kjunine -DartifactId=sample -Dpackage=net.kjunine.sample -Dversion=1.0-SNAPSHOT

위 명령어에서 archetype:generate는 archetype 플러그인의 generate 골(Goal)이라는 것인데, 플러그인과 골은 지금은 몰라도 좋다. 그냥 프로젝트를 생성하는 옵션이라고 생각하면 된다. -D로 시작하는 것들은 생성할 프로젝트에 대한 정보를 나타내는 파라메터들이다. 각 파라메터는 다음을 의미한다.

  • groupId
    • 프로젝트를 만드는 그룹, 조직, 회사 등을 나타내는 유일한 이름, 보통 자바 패키지처럼 URI를 거꾸로 써서 나타낸다.
  • artifactId
    • 아티팩트(artifact) 즉, 프로젝트를 나타내는 유일한 이름, 그룹 내 다른 아티팩트와 이름이 같아서는 안된다.
  • package
    • 프로젝트의 최상위 패키지
  • version
    • 프로젝트의 현재 버전

프로젝트 생성이 성공하면, 명령어를 수행한 폴더 내에 artifactId 이름과 동일한 폴더가 생긴다. 그 폴더로 들어가면 다음과 같이 src 폴더와 pom.xml 파일을 볼 수 있다.

pom.xml 파일은 바로 Project Object Model(POM)이라는 것으로 메이븐 프로젝트에 대한 모든 설정을 저장하는 파일이다. 메이븐 프로젝트의 모든 것이다. 그 파일을 열어보면 다음과 같을 것이다. 앞서 프로젝트 생성 시 설정한 프로젝트 옵션 값들이 저장되어 있는 것을 볼 수 있다.

03.  <modelVersion>4.0.0</modelVersion>
04.  <groupId>net.kjunine</groupId>
05.  <artifactId>sample</artifactId>
06.  <packaging>jar</packaging>
07.  <version>1.0-SNAPSHOT</version>
08.  <name>sample</name>
09.  <url>http://maven.apache.org<;/url>
10.  <dependencies>
11.    <dependency>
12.      <groupId>junit</groupId>
13.      <artifactId>junit</artifactId>
14.      <version>3.8.1</version>
15.      <scope>test</scope>
16.    </dependency>
17.  </dependencies>
18.</project>

3. 라이브러리 의존 관계를 설정한다.

POM에서 지금 관심을 가져야 할 부분은 바로 <dependencies /> 부분이다. 여기에서 프로젝트의 의존 관계를 설정할 수 있다. 현재 JUnit 라이브러리는 자동으로 추가되어 있는 것을 볼 수 있다. 여기에 Commons Lang 라이브러리도 추가하자. <dependencies /> 부분을 다음과 같이 바꾸면 된다. <dependency /> 항목을 하나 추가하는 것으로 라이브러리를 추가할 수 있다. 정말 편하지 않은가?! +_+

01.<dependencies>
02.  <dependency>
03.    <groupId>commons-lang</groupId>
04.    <artifactId>commons-lang</artifactId>
05.    <version>2.4</version>
06.  </dependency>
07.  <dependency>
08.    <groupId>junit</groupId>
09.    <artifactId>junit</artifactId>
10.    <version>3.8.1</version>
11.    <scope>test</scope>
12.  </dependency>
13.</dependencies>

해당 라이브러리의 groupId와 artifactId는 어떻게 알 수 있는지 궁금할 것이다. 의외로 간단하다. Maven Repository 홈페이지에서 검색하면 된다. 다만 가끔 비슷한 게 많이 나와서 어떤 걸 써야할지 모를 때도 있다. (예를 들면, springframework) 그럴 때는 해당 라이브러리 홈페이지에서 정확한 메이븐 groupId와 artifactId를 찾아보던가 구글링할 수 밖에 없는 것 같다. 아직 내공이 부족하다. ㅠ_ㅠ

4. 자바 소스와 테스트를 작성한다.

프로젝트 폴더 내 src 폴더에 보면 main 폴더와 test 폴더가 있는데 각각 자바 소스 파일과 테스트 파일들이 존재하는 곳이다. 메이븐은 이렇게 정해진 폴더 구조와 이름을 강제로 사용하게 해서 프로그래머의 고민을 덜어준다. 하지만 바꿀 수도 있는 것 같다.

각 소스 폴더와 테스트 폴더에는 프로젝트 생성 시에 설정한 패키지 이름대로 폴더 구조가 만들어져 있고, 각각 App.java 파일과 AppTest.java 파일이 존재한다. 두 파일을 사용할 것은 아니니 삭제하자.

그리고 소스 폴더의 해당 패키지에 다음 클래스 파일를 작성하자.

Sample.java

01.package net.kjunine.sample;
02.  
03.import org.apache.commons.lang.StringUtils;
04.  
05.public class Sample {
06.  
07.    public static String reverse(String s) {
08.        return StringUtils.reverse(s);
09.    }
10.  
11.    public static void main(String[] args) {
12.        for (int i = 0; i < args.length; i++) {
13.            System.out.println(reverse(args[i]));
14.        }
15.    }
16.  
17.}

Commons Lang 라이브러리의 StringUtils 유틸 클래스가 제공하는 reverse 메소드를 사용하여 입력받은 문자열들을 거꾸로 출력하는 프로그램을 만들었다.

테스트 폴더의 해당 패키지에 위 클래스에 대한 테스트 클래스 파일도 작성하자.

SampleTest.java

01.package net.kjunine.sample;
02.  
03.import junit.framework.TestCase;
04.  
05.public class SampleTest extends TestCase {
06.  
07.    public void testReverse() {
08.        String actual = Sample.reverse("hello");
09.        String expected = "olleh";
10.        assertEquals(expected, actual);
11.    }
12.  
13.}

JUnit 라이브러리를 사용한 간단한 테스트 클래스이다.

5. 프로젝트를 빌드한다.

프로젝트를 빌드하는 것은 간단하다. 프로젝트 폴더에서 다음 명령어를 실행하면 된다.

 mvn install

이 명령어를 이해하려면 메이븐에서 말하는 빌드 생명주기(Build Lifecycle)라는 개념을 알아야 한다. 빌드 생명주기는 일련의 프로젝트 빌드 단계(Build Phase)들의 (순서있는) 집합이다. 빌드 단계는 compile, test, package, deploy 등과 같은 프로젝트를 빌드하는데 거치는 단계들을 의미한다. 그리고 각 빌드 단계마다 무슨 일을 해야하는지가 정해져 있다. 허접한 설명이라 더 자세한 내용은 여기를 참조하자. (메이븐 책을 봐도 좋다.)

위 명령어는 생명주기에서 install 단계까지의 전 단계를 실행하라는 것으로 compile, test, package, install 등의 단계들을 포함한다.

그래서 위 명령어를 실행하면 중간에 다음과 같이 테스트 결과가 나온다. 그리고 빌드가 성공하면 "BUILD SUCCESSFUL"이 보일 것이다.

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running net.kjunine.sample.SampleTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.031 sec

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO] [jar:jar]
[INFO] Building jar: D:\dev\workspaces\maven\sample\target\sample-1.0-SNAPSHOT.jar
[INFO] [install:install]
[INFO] Installing D:\dev\workspaces\maven\sample\target\sample-1.0-SNAPSHOT.jar to ...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------

또, 프로젝트 폴더 내 target 폴더에 생성된 클래스 파일들과 테스트 파일들 등이 들어있는 폴더들과 함께 jar 형태로 묶인 프로젝트 패키지 파일이 보인다.

6. 프로그램을 실행한다.

테스트도 성공하고 패키지 파일도 생성했으니 이제 실행만 하면 된다. 다음 명령어를 실행하라.

java -cp target/sample-1.0-SNAPSHOT.jar;"%HOME%/.m2/repository/commons-lang/commons-lang/2.4/commons-lang-2.4.jar" net.kjunine.sample.Sample hello kjunine

생각보다 실행 방법이 까다로운데 이것은 아직 플러그인을 배우지 않았기 때문이니 지금은 그냥 참고 넘어가자. %HOME%/.m2/repository 폴더는 메이븐이 라이브러리와 플러그인을 다운로드해서 저장하는 로컬 저장 폴더이다. 그리고 Commons Lang 라이브러리는 위와 같은 경로에 존재한다. 실행 시에 Commons Lang 라이브러리를 사용하기 때문에 클래스패스에 추가한 것이다.

실행 결과는 다음과 같다.

olleh
eninujk

굳~

이제 겨우 걸음마를 시작했을 뿐..

아직 메이븐에 대해 공부할 것은 많이 남아 있다. 플러그인과 골의 개념을 이해하고 POM에 설정할 수 있어야 한다. 그리고 이클립스에서 개발하기 위해 메이븐 이클립스 플러그인(maven-eclipse-plugin)을 사용하거나, 아니면 m2eclipse, Q4E와 같은 이클립스 플러그인을 사용할 수 있어야 한다. 실제 프로젝트를 진행할 때는 지금처럼 명령어에서 실행하기보다는 이클립스 플러그인을 사용하는 것이 훨씬 쉽고 간편할 것이다.

방금 말한 내용들은 다음 포스트들에서 다룰 것이다. 이미 제목은 써놓았다. 다만 언제 완성될지는.. ^^;