JAVA & Open Framework2013. 2. 14. 00:09

Maven 은 간단하게 말하자면 Project Management Framework 라고 할 수 있다...

POM(Project Management Object)이란 녀석을 이용하여 빌드에서부터 시작해서 의존성 관리 및 배포까지 모든 것을 관리할 수 있다..

Maven을 이용하면 Coherence, Reusability, Agility, Maintainability 등을 제공한다고 한다...

아직 잘 모르면서 그냥 쓰고 있기 때문에 저런 장점을 제공하는지는 잘 모르겠다... -_-;;

대체 Maven이 어떤 철학을 가지고 있길래 저런 것들을 제공하는지 한 번 알아보자...


1. Convention Over Configuration

관념이 설정보다 우선한다는 말인데 이게 대체 무슨 말인가...

Ruby on Rails 에서 유명하게 된 말이라고 하는데 간단하게 말하자면 디폴트로 뭔가 정해 놓고 그건 신경쓰지 말고 쓰자는 말이다..

물론 설정을 통해 자신이 원하는대로 변경할 수 있지만 신경 쓸 필요 없는 걸 구지 신경쓰지 말잔 말이다..

Maven 에서는 다음과 같은 3가지를 제공하면서 위의 철학을 실현하고 있다..


Standard Directory Layout

말 그대로 디렉토리 구조를 미리 정해 놓은 것이다. 소스파일, 설정파일, 빌드파일, 도큐먼트 등의 위치를 정해놓고 그대로 쓰자는 얘기다.


Separation Of Concerns

하나의 프로젝트에서는 하나의 결과물을 가지도록 하는 것이다. 이를 통해 재사용성을 증가시킬 수 있다. 이는 바로 다음에 살펴볼 빌드 로직을 재사용하는 것에서 쉽게 확인할 수 있다.


Standard Naming Conventions

디렉토리와 결과물의 이름 규칙도 정해져 있다. 예를 들어 commons-loggin-1.2.jar 란 파일이 있다고 하면 commons logging의 버전 1.2를 사용한다는 것을 쉽게 알 수 있다. 자바의 get/set 메소드도 하나의 예라고 할 수 있다.


2. Reuse of Build Logic


Maven에서는 빌드를 위해 필요한 로직을 플러그인이란 이름의 모듈로 구현해 놓았다. 이런 플러그인에는 컴파일, 테스트, 패키징, 문서화등등 수 많은 플러그인들이 존재한다. 여기서 아주 중요한 사실은 Maven은 이와 같은 플러그인들의 실행 결과를 모아서 최종 결과를 낸다는 것이다. 이런 플러그인들을 Maven의 설정 파일인 POM(Project Object Model)에 설정하게 되고 Build Life Cycle에 따라 플러그인들이 순서대로 실행되어 최종 결과물을 출력하게 된다.


3. Declarative Execution


위에서 잠깐 알아보았듯이 Maven에서는 POM(Project Object Model)에 모든 설정을 하게 된다. 그러면 POM이 무엇이고 잠깐 살펴본 Build Life Cycle이 무엇인지 알아보도록 하자.


POM(Project Object Model)


Maven에서는 하나의 프로젝트에 하나의 POM을 가진다. POM은 XML 형태로 구성되어 있고 아래는 아주 간단한 예제이다.


<project>

<modelVersion>4.0.0</modelVersion>

<groupId>com.mycompany.app</groupId>

<artifactId>my-app</artifactId>

<packaging>jar</packaging>

<version>1.0-SNAPSHOT</version>

<dependencies>

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>3.8.1</version>

<scope>test</scope>

</dependency>

</dependencies>

</project>


위의 15줄에 불과한 POM을 사용하면 컴파일, 테스트 및 문서화까지도 가능하다. 어떻게 이런 일이 가능할까... 왜냐하면 Maven은 묵시적으로 Super POM을 사용하기 때문이다. 자바의 Object 클래스와 같은 역할을 한다고 보면 된다. 그렇다면 각각의 속성에 대해 간단하게 알아보도록 하자.


<project> - pom.xml 파일의 ROOT. 무조건 이 속성으로 시작해야 한다.

<modelVersion> - 현재 POM이 사용하고 있는 버전을 나타낸다. 이 버전은 자기 마음대로 정해주면 되는데 적당히 잘 해주도록 하자.

<groupId> - 프로젝트를 만든 조직이나 그룹의 유일한 식별자이다. 보통 자바 패키지 만드는 형식으로 지정해주면 된다. 물론 안 그렇게 해도 된다.

<artifactId> - 프로젝트에서 생성하는 결과물의 이름에 사용되는 속성이다. Maven에서는 <artifactId>-<version>.<extension> 같은 형식의 파일 이름으로 패키징 해준다. 위의 예제는 my-app-1.0-SNAPSHOT.jar 와 같은 형태로 만들어지게 된다.

<packaging> - 패키징 할 파일 형식을 지정한다. (JAR, WAR, EAR 등등) 뿐만 아니라 빌드 프로세스의 부분으로 사용하기 위한 특정 Life Cycle을 나타내기도 한다. 그냥 Build Life Cycle을 커스터마이징 할 때 사용된다고 알아두면 된다고 한다. -_-;;

<version> - 프로젝트의 버전을 표시한다. 위에 SNAPSHOT이라고 붙은 것은 개발 상태일 때 붙인다고 한다.

<name> - 프로젝트의 이름

<url> - 프로젝트 사이트

<description> - 프로젝트 설명


다른 자세한 내용은 http://maven.apache.org/maven-model/maven.html 여기에 가면 확인할 수 있다. 일단 이정도 까지만 살펴보고 나머지는 뒤에 나올 것 같으니 일단 넘어가도록 하자...


Build Life Cycle


그렇다면 계속 말이 나오던 Build Life Cycle에 대해서 알아보자.

일반적으로 소프트웨어 프로젝트는 컴파일, 테스트, 패키징, 인스톨과 같은 전형적인 단계를 갖는다.

Maven에서는 이러한 단계들을 Build Life Cycle이라고 부른다.

Maven의 Build Life Cycle은 크게 compile, test, package, install 등과 같은 goal 들로 구성된다.

특정한 goal 을 실행할 때 하위 레벨에 실행해야 할 goal 들이 있다면 하위 레벨의 goal 들이 먼저 실행된다.

예를 들어 클래스들을 컴파일하기 위해 compile goal 을 실행하게 되면 하위 레벨의 goal 들인 validate, initialize, generate-sources, process-sources, generate-resources 를 실행한 후에 complie goal 을 수행하게 된다.

이처럼 Build Life Cycle은 많은 단계들로 구성되어 있고 또한 이를 확장할 수도 있다.

Build Life Cycle의 하나의 단계는 하나의 플러그인으로 만들어지고 해당 플러그인은 해당 goal 을 실행하게 된다.

(실제로 compile goal은 compiler 플러그인이 담당하고 있고 test goal은 surefire 플러그인이 담당한다.)


4. Coherent Organization of Dependencies


이번에는 Maven에서 의존성 관리를 어떻게 해주는지 살펴보도록 하자. 아까 살펴본 POM 예제를 다시 살펴보도록 하자.


<project>

<modelVersion>4.0.0</modelVersion>

<groupId>com.mycompany.app</groupId>

<artifactId>my-app</artifactId>

<packaging>jar</packaging>

<version>1.0-SNAPSHOT</version>

<dependencies>

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>3.8.1</version>

<scope>test</scope>

</dependency>

</dependencies>

</project>


딱 보면 알 수 있듯이 junit 란 녀석에게 의존성을 갖는 것을 알 수 있다.

의존성이란 Repository 에 존재하는 특정 라이브러리 파일에 대한 참조를 말한다.

Maven에서는 이런 의존성을 해결하기 위해 어떤 라이브러리 파일을 어떤 Repository를 살펴봐야 하는지 정보가 필요하다.

이런 것들은 groupId, artifactId, version 속성을 사용해서 식별하게 된다.

라이브러리가 물리적으로 어디에 존재하는지 또한 파일을 다운로드 받을 필요도 없다.

그저 위에서 처럼 설정만 하면 junit (groupId) 에서 제공하는 junit (artifactId) 의 3.8.1 (version) 에 의존성이 있다고 명시만 하면 된다..

그렇게 하면 Maven에서 이용 가능한 모든 Remote Repository를 뒤져서 사용자의 Local Repository로 복사해준다.

Maven에는 방금 살펴본대로 2가지 Repository가 존재한다.

Remove Repository는 말 그대로 해당 라이브러리를 다운로드 받을 수 있는 곳을 말한다.

Local Repository는 Maven을 처음 설치하고 실행하게 되면 모든 의존성이 있는 라이브러리를 모아 놓는 곳이다.

기본적으로 사용자의 홈 디렉토리에 ~/.m2/repository 요런 식으로 생성되게 된다.

위의 의존성을 해결하게 되면 사용자 홈 디렉토리에 다음과 같은 형식으로 해당 라이브러리 파일이 저장되게 된다.


repository

└ groupId

└ artifactId

└ version

├ artifactId-version.jar

├ artifactId-version.jar.sha1

├ artifactId-version.pom

└ artifactId-version.pom.sha1


만약 groupId가 org.apache.maven 이라면 자바의 패키지 생성과 같은 방식으로 org - apache- maven 디렉토리가 생성되고 그 아래에 나머지 구조대로 생성되게 된다.

Maven은 이처럼 의존성을 해결할 때 먼저 Local Repository에 /repository/groupId/artifactId/version/artifactId-version.jar 파일이 존재하는지 확인한다.

만약 존재하지 않는다면 Remote Repository에서 다운로드 받아 Local Repository의 해당 위치에 복사하게 된다.

Maven은 Remote Repository로 http://www.ibiblio.org/maven2 를 기본으로 사용한다.

또한 Maven은 여러 개의 Remote Repository를 가질 수 있는데 POM에 정의된 순서대로 찾아가게 된다.

이렇게 Local Repository를 사용하면 여러 개의 프로젝트에서 같은 파일을 사용해도 하나의 파일만 존재하면 된다.

또한 버전별로 관리할 수 있으므로 쓸데 없는 라이브러리를 프로젝트에 추가하지 않을 수 있게 된다.


휴.. 이렇게 대충 Maven이 어떤 것이고 어떤 구조를 가지고 있으며 무슨 생각으로 이렇게 만들었는지 살펴보았다...

다음번에는 실제로 Maven을 사용해보도록 하자!!

 

출처 : http://nadostar.egloos.com/176414

Posted by 아로나