상세 컨텐츠

본문 제목

[Maven] 소개

Devops 도전기/Maven

by 끝까지해봐야지 2024. 5. 17. 21:14

본문

 

 

Apache Maven은 소프트웨어 프로젝트 관리 및 이해 도구입니다. 프로젝트 객체 모델(Project Object Model, POM)이라는 개념을 바탕으로 프로젝트의 빌드, 의존성 관리, 문서화, 사이트 게시 및 배포 게시를 모두 pom.xml 선언적 파일에서 제어합니다. 플러그인을 통해 Maven을 확장하여 보고 또는 빌드 프로세스를 위한 다른 여러 개발 도구를 활용할 수 있습니다. 또한, Java용 프로젝트 관리 도구로서 프로젝트 라이프사이클 관리 기능과 같은 기능을 제공하며, Apache Ant의 대안으로 개발되었습니다. 따라서 Ant와 마찬가지로 프로젝트의 소스 코드를 컴파일(Compile), 테스트(Test), 패키지(Package)할 수 있습니다.

Apache Maven 팀은 마지막 두 GA 릴리즈(3.8.8, 3.9.2)의 최신 버전을 유지 관리합니다. 현재 Apache Maven 3.9.4가 최신 릴리스 버전이며 JDK 8 이상이 필요합니다. JDK 5에서는 Maven 3.1.1 버전, JDK 6에서는 3.2.5 버전이 최종 버전입니다. Maven Releases History 페이지에서 Maven 버전별 필요한 Java 버전을 확인합니다.

버전을 확인했으면 Download 페이지에서 다운로드 받아 설치할 수 있습니다.

POM

POM은 "프로젝트 객체 모델"의 약자입니다. 이는 pom.xml이라는 파일에 저장된 Maven 프로젝트의 XML 표현입니다. Maven 사람들 앞에서 프로젝트에 대해 말하는 것은 단순히 코드가 포함된 파일 모음을 넘어 철학적 의미로 말하는 것입니다. 프로젝트에는 구성 파일뿐만 아니라 참여한 개발자와 역할, 결함 추적 시스템, 조직 및 라이선스, 프로젝트가 있는 위치의 URL, 프로젝트의 의존성 및 코드에 생명을 불어넣는 기타 모든 작은 요소들이 포함되어 있습니다. 프로젝트에 관한 모든 것을 원스톱으로 확인할 수 있는 곳입니다. 실제로 Maven 세계에서는 프로젝트에 코드가 전혀 포함될 필요 없이 단지 pom.xml만 있으면 됩니다.

기본 요소

아래 POM은 Maven이 허용하는 최소한의 구성입니다. groupId:artifactId:version은 모두 필수 필드입니다. (하지만 groupId 및 version은 parent로부터 상속되는 경우, 명시적으로 정의할 필요가 없습니다.) 세 개의 필드는 하나의 주소와 타임스탬프처럼 작동합니다. 이것은 Maven 프로젝트의 좌표계처럼 작동하는 저장소의 특정 위치를 표시합니다.

  • project : 모든 Maven  파일의 최상위 요소입니다.
  • pom.xml
  • modelVersion : 이 요소는 이 POM이 사용 중인 개체 모델의 버전을 나타냅니다. 모델 자체의 버전은 매우 드물게 변경되지만 Maven 개발자가 모델 변경이 필요하다고 판단되는 경우 사용의 안정성을 보장하기 위해 필수(mandatory)입니다.
  • groupId : 이 요소는 프로젝트를 생성한 조직 또는 그룹의 고유 식별자를 나타냅니다. dot(.) 표기법의 groupId는 프로젝트가 포함된 패키지 구조와 일치할 필요는 없지만 따르는 것이 좋은 방법입니다. 일반적으로 도메인 이름을 역으로 표기합니다.
  • artifactId : 이 요소는 이 프로젝트에 의해 생성되는 기본 아티팩트의 고유한 기본 이름을 나타냅니다. 프로젝트의 기본 아티팩트는 일반적으로 JAR 파일입니다. 소스 번들과 같은 보조 아티팩트도 최종 이름의 일부로 artifactId를 사용합니다. Maven에서 생성된 일반적인 아티팩트는  형식을 갖습니다. (예: )myapp-1.0.jar
  • <artifactId>-<version>.<extension>
  • version : 이 요소는 프로젝트에서 생성된 아티팩트의 버전을 나타냅니다. Maven은 버전 관리에 많은 도움이 되며 프로젝트가 개발 상태에 있음을 나타내는  지정자를 버전에서 자주 볼 수 있습니다.
  • SNAPSHOT
  • packaging : 이 요소는 아티팩트에서 사용할 패키지 유형을 나타냅니다. (예: , )war
  • jar
  • name : 이 요소는 프로젝트에 사용되는 표시 이름을 나타냅니다. 이것은 Maven의 생성 문서에서 자주 사용됩니다.
  • description: 프로젝트에 대한 간략한 설명을 나타냅니다.
  • url: 프로젝트 홈페이지의 URL 입니다.
    4.0.0

    net.infograb.demo
    sample
    0.0.1-SNAPSHOT
    war
    Sample Maven Webapp

...🎉

Properties

Maven 프로퍼티(properties)은 Ant의 프로퍼티와 마찬가지로 설정 파일 내에서 반복적으로 사용되는 상수 값을 정의할 때 사용합니다. 해당 값은 ${X} 표기법을 사용하여 POM 내 어디에서나 액세스할 수 있습니다. 여기서 X은 프로퍼티입니다. 또는 플러그인에서 기본값으로 사용할 수 있습니다.

...

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <servlet.version>3.0.1</servlet.version>
        <spring.version>3.2.11.RELEASE</spring.version>
        <slf4j.version>1.7.7</slf4j.version>
        <logback.version>1.1.2</logback.version>
        <jackson.version>2.4.3</jackson.version>
    </properties>

...🎉

Dependencies

Maven을 사용하기 이전의 Java Web 프로젝트에서는 직접 필요한 라이브러리를 다운로드 받아서 WEB-INF/lib에 위치시키고 IDE에 path를 설정하고 사용하였습니다. 직접 라이브러리를 찾고 설정하는 번거로움과 라이브러리의 버전을 관리하기가 어렵습니다. 또한, Excel 문서를 처리하는 Apache POI와 REST API 요청 시 사용하는 Apache HttpComponents의 HttpClient 라이브러리는 의존성 라이브러리를 동일하게 Apache Commons Codec을 참조합니다. 참조하는 버전이 다르면 에러가 발생합니다.

Maven은 의존성 관리 기능을 통해 이러한 문제를 해결합니다.

...
    <dependencies>
...
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
...🎉

  • groupId, artifactId, version : 이 삼위일체는 특정 프로젝트의 Maven 좌표를 시간 내에 계산하는 데 사용되며, 이 프로젝트의 의존성으로 구분합니다.
  • scope : 이 요소는 현재 작업(컴파일 및 런타임, 테스트 등)의 클래스 경로와 의존성의 전이성을 제한하는 방법을 나타냅니다. 5가지 범위를 사용할 수 있습니다.
    • compile - 아무 것도 지정되지 않은 경우 사용되는 기본 범위입니다. 컴파일 의존성은 모든 클래스 경로에서 사용할 수 있습니다. 또한 이러한 의존성은 의존 프로젝트에 전파됩니다.
    • provided - 이것은 컴파일과 매우 유사하지만 런타임에 JDK 또는 컨테이너가 이를 제공할 것으로 예상한다는 것을 나타냅니다. 컴파일 및 테스트 클래스 경로에서만 사용할 수 있으며 전이되지 않습니다.
    • runtime - 이 범위는 의존성이 컴파일에는 필요하지 않지만 실행에는 필요함을 나타냅니다. 런타임 및 테스트 클래스 경로에 있지만 컴파일 클래스 경로에는 없습니다.
    • test - 이 범위는 의존성이 애플리케이션의 일반적인 사용에 필요하지 않으며, 테스트 컴파일 및 실행 단계에서만 사용할 수 있음을 나타냅니다. 그것은 전이적이지 않습니다.
    • system - 이 범위는 명시적으로 포함하는 JAR을 제공해야 한다는 점을 제외하고 와 유사합니다. 아티팩트는 항상 사용 가능하며 저장소에서 조회되지 않습니다.
    • provided

Profiles

Maven 프로파일은 프로젝트가 구축되는 환경에 따라 설정을 변경할 필요가 있는 경우, 특정 빌드 환경에 맞춘 리소스의 재배치 및 환경에 대한 옵션을 설정할 수 있는 기능입니다. 예를 들어, 테스트 환경을 위해 구축된 프로젝트는 운영 환경에 배포되는 것과 다른 데이터베이스를 가리킬 수 있습니다.

mvn install -P[profile명]와 같이 -P 옵션으로 실행하거나, activation 요소를 사용하여 activeByDefault을 true로 설정하면 기본 프로파일로 활성화됩니다.

...
    <profiles>
        <profile>
            <id>local</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <env>local</env>
            </properties>
        </profile>
        <profile>
            <id>dev</id>
            <properties>
                <env>dev</env>
            </properties>
        </profile>
        <profile>
            <id>prod</id>
            <properties>
                <env>prod</env>
            </properties>
        </profile>
    </profiles>
..🎉

Build

build 요소는 프로젝트의 디렉토리 구조를 선언하고 빌드에서 사용할 플러그인 관리를 처리합니다.

...
    <build>
        <directory>${project.basedir}/target</directory>
        <finalName>${project.artifactId}-${project.version}</finalName>
        <sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
        <testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory>
        <outputDirectory>${project.build.directory}/classes</outputDirectory>
        <testOutputDirectory>${project.build.directory}/test-classes</testOutputDirectory>
        <filters>
            <filter>filters/config-${env}.properties</filter>
        </filters>
        <resources>
            <resource>
                <filtering>true</filtering>
                <directory>${project.basedir}/src/main/resources</directory>
            </resource>
        </resources>
        <testResources>
            <testResource>
                <directory>${project.basedir}/src/test/resources</directory>
            </testResource>
        </testResources>
        ...
  <build>
...🎉

  • ${project.basedir} : pom.xml 파일이 포함된 디렉토리
  • 💡 그 외의 ${project.*} 속성은 POM의 <project> 요소를 기준으로 설정하여 계산된 값으로 대체하도록 구성할 수 있습니다. 예를들어, ${project.version}, ${project.build.finalName}, ${project.artifactId}, ${project.build.directory}와 같이 사용할 수 있습니다.
  • directory : 빌드 결과로 생성되는 파일들이 위치할 디렉토리. 정의하지 않으면 기본값으로 ${project.basedir}/target이 적용됩니다.
  • finalName : 빌드 후 패키지 결과로 생성되는 번들 파일명. (파일 확장자 제외) 정의하지 않으면 기본값 ${project.artifactId}-${project.version}가 적용됩니다. 예를들어, 패키징 결과로 my-project-1.0.jar이 생성됩니다.
  • Directory : 프로젝트의 디렉토리 구조를 정의합니다. 프로젝트에서 기본값을 사용하지 않는 경우, 재정의하여 사용합니다.
    • sourceDirectory : Java 소스 파일들이 있는 디렉토리
    • testSourceDirectory : JUnit을 이용한 단위 테스트 코드와 같은 Java 테스트 소스 파일들이 있는 디렉토리
    • outputDirectory : sourceDirectory의 소스를 컴파일한 결과물이 위치하는 디렉토리
    • testOutputDirectory : testSourceDirectory의 소스를 컴파일한 결과물이 위치하는 디렉토리
  • filters : 필터링 설정을 수락하는 리소스에 적용되며, 프로퍼티(properties) 목록을 포함하는 .properties 파일을 정의합니다. 즉, 필터 파일 내에 정의된 name=value 쌍이 빌드 시 리소스 내의 ${name} 문자열을 대체합니다.
  • 💡 예제에서는 filters/config-local.properties, filters/config-dev.properties, filters/config-prod.properties 파일에 정의되어 있는 jdbc.url = jdbc:mysql://localhost:3306/my_db?useUnicode=true&characterEncoding=utf8와 같은 값이 src/main/resources/config.properties 파일 내에 정의되어 있는 jdbc.url = ${jdbc.url} 값을 대체합니다.
  • resources : .xml, .properties와 같은 리소스 파일들을 포함할 항목과 위치를 지정하는 요소
    • filtering : 이 리소스에 대해 필터링을 활성화할지 여부
    • directory : 이 리소스가 위치할 디렉토리 지정
  • testResources : testResource 요소를 포함하며, resource 요소와 유사하지만 테스트 단계에서만 사용됩니다.

예제 프로젝트에서는 finalName, filters, resources 요소들을 재정의하여 사용하였습니다.

...
    <build>
        <finalName>ROOT</finalName>
        <filters>
            <filter>filters/config-${env}.properties</filter>
        </filters>
        <resources>
            <resource>
                <filtering>true</filtering>
                <directory>${project.basedir}/src/main/resources</directory>
            </resource>
        </resources>
        ...
  <build>
...🎉

Maven에서 제공되는 모든 기능은 플러그인에 의해 수행됩니다.

Build 플러그인을 지정하지 않아도 mvn [Phase] 형태로 명령을 실행하면, Maven이 각 단계(Phase)에 연결된 플러그인 정보를 알고 있기 때문에 해당 플러그인을 자동으로 다운로드 받아 실행합니다.

compile 단계을 실행하면 compiler 플러그인, package 단계을 실행하면 war 플러그인에 의해 자동적으로 수행됩니다.

예제 프로젝트에서는 compiler 플러그인의 구성에 source, target의 JDK 버전을 추가 정의하였습니다.

...
    <build>
        ...
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
...

'Devops 도전기 > Maven' 카테고리의 다른 글

[Maven] 명령과 옵션  (0) 2024.05.17
[Maven] build lifecycle 이란?  (0) 2024.05.17

관련글 더보기