# Table of Contents

# pom.xml

모든 Maven 프로젝트는 pom.xml파일을 포함한다. 이 파일에는 프로젝트를 빌드하는데 필요한 정보들이 나열되어있다.

# 프로젝트 기본 정보

<project xmlns="http://maven.apache.org/POM/4.0.0" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.yologger.project</groupId>
    <artifactId>maven_project</artifactId>
    <version>0.0.1</version>
    <name>maven_project</name>
    <packaging>jar</packaging>
    <url>http://maven.apache.org</url>

</project> 
  • <project>: 최상위 태그
  • <modelVersion>: pom.xml 파일의 버전이며, 항상 4.0.0 값으로 설정한다.
  • <groupId>: 조직의 고유 id를 입력한다. 보통 조직 도메인 네임의 역순을 입력한다.
  • <artifactId>: 애플리케이션을 구분하는 고유 id를 입력한다.
  • <version>: 해당 artifact의 버전을 입력한다.
  • <packaging>: 어떤 파일 형식으로 패키징할지 정의한다. jar, war, exe 등이 올 수 있다.
  • <name>: 애플리케이션의 이름을 입력한다.

# 의존성

<dependencies>태그를 사용하면 외부 의존성을 추가할 수 있다. 다음 예제에서는 JUnit 라이브러리를 추가하고있다.

<project>

    <!-- .. -->

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

Maven의 의존성은 scope를 가진다. scope의존성의 적용 범위를 제한하는데 사용한다. 예를 들어 scope를 사용하면 의존성을 컴파일 과정에만 적용할 수 도 있고, 런타임에만 적용할 수 있다.

  • compile: 컴파일 타임과 런타임에 모두 필요한 의존성이다. spring-context.jar, spring-webmvc.jar가 대표적이다.
  • provided: 컴파일 타임과 런타임에 모두 필요하지만, 런타임에서는 JDK나 Tomcat의 의존성을 사용한다. 예를 들어 JSP(jsp-api.jar), Servlet(servlet-api.jar)은 컴파일 과정에서 필요하지만 런타임 환경에서는 Tomcat에서 제공하는 라이브러리를 사용한다.
  • runtime: 컴파일 타임에서는 필요없으나 런타임에서는 필요한 의존성이다. 예를 들어 JDBC Driver(mysql-connector-java.jar)가 대표적이다.
  • test: 테스트 코드를 컴파일할 때는 의존성을 포함하지만 배포할 때는 제외한다. JUnit(junit.jar)가 대표적이다.

# 추이적 의존성

의존성을 다른 의존성을 가질 수 있다. 예를 들어 spring-context.jar는 다른 의존성을 가지고 있다. 이를 추이적 의존성이라고 한다.

spring-context.jar
├───── spring-core.jar
├───── spring-aop.jar
├───── spring-beans.jar
├───── spring-asm.jar
└───── spring-asm.jar

추이적 의존성은 문제를 일으킬 수 있다. 아래 그림을 보자. Dependency A와 Dependency B는 모두 Dependency C에 의존하고 있다.

만약 Dependency C는 버전이 다르다면 어떻게 될까?

이러한 경우 문제가 발생할 수 있기 때문에 다음과 같이 의존 관계를 수정해야한다.

이때 Dependency A와 Dependency B에서 <exclusion>태그를 사용하여 Dependency C를 제외할 수 있다. 아래 예제에서는 spring-context.jar에서 commons-logging.jar를 제외하고 있다.

<!-- pom.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
    <!-- ... -->

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${org.springframework-version}</version>
            <exclusions>
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>			 
    </dependencies>

</project>

# properties 태그

<properties>태그는 pom.xml 파일 내에서 반복적으로 사용되는 상수를 정의할 때 사용한다.

<project>

    <!-- properties -->
    <properties>
        <junit-version>3.8.1</junit-version>
        <org.springframework-version>3.1.1.RELEASE</org.springframework-version>
    </properties>

    <!-- dependencies -->
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit-version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${org.springframework-version}</version>
            <exclusions>
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                </exclusion>
            </exclusions>
            <scope>provided</scope>
        </dependency>
    </dependencies>

</project>

# build 태그

<build>태그 내부에는 Maven이 프로젝트를 빌드할 때 필요로 하는 정보를 나열한다.

<project>
    <build>
        <sourceDirectory>src/main/java</sourceDirectory>
        <testSourceDirectory>src/test/java</testSourceDirectory>
        <outputDirectory>${project.basedir}/target/classes</outputDirectory>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                    <compilerArgument>-Xlint:all</compilerArgument>
                    <showWarnings>true</showWarnings>
                    <showDeprecation>true</showDeprecation>
                </configuration>
            </plugin>
            </plugin>
        </plugins>
    </build>
</project>
  • <build>: 빌드 시 사용할 옵션을 나열한다.
  • <sourceDirectory>: 자바 소스 코드를 관리하는 디렉토리
  • <testSourceDirectory>: 테스트 소스를 관리하기 위한 디렉토리
  • <outputDirectory>: sourceDirectory의 소스를 컴파일한 결과물이 위치하는 디렉토리
  • <testOutputDirectory>: testSourceDirectory의 소스를 컴파일한 결과물이 위치하는 디렉토리
  • <resources>: 프로젝트에서 사용하는 자원이 위치하는 디렉토리. 이 디렉토리에 포함된 파일들은 빌드 시 포함됩니다.
  • <testResources>: 테스트에서 사용하는 자원이 위치하는 디렉토리
  • <plugins>: 플러그인은 Maven이 애플리케이션을 빌드할 때 사용하는 도구다. 이 태그 안에 사용할 플러그인을 나열한다. 모든 Maven 플러그인은 이 곳 (opens new window)에서 확인할 수 있다.

# Repository 태그

의존성을 다운받을 원격 저장소를 나열한다. 별도로 기술하지 않을 때는 Maven 저장소 (opens new window)가 기본적으로 사용된다.

조직에서 사용하는 사설 저장소가 있다면 다음과 같이 추가할 수 있다. 자주 사용되는 메이븐 사설 저장소에는 JBoss 저장소 (opens new window), Spirng 저장소 (opens new window)가 있다.

<project>
    <!-- .. -->

    <!-- Repository -->
    <repositories>
        <repository>
            <id>springsource-repo</id	
            <url>http://repo.springsource.org/release</url>
        </repository>
        <repository>
            <id>jboss-repo</id>
            <url>https://repository.jboss.org/nexus/content/groups/public/</url>
        </repository>
    </repositories>

</project>

원격 저장소에서 다운받은 의존성은 로컬 저장소에 저장된다. 로컬 저장소의 위치는 보통 /[user_home_directory]/.m2/repository에 위치한다.

$ pwd
/yologger/.m2/repository

$ ls
antlr                    classworlds              commons-collections      dom4j                    net                      xpp3
aopalliance              com                      commons-digester         index                    org
asm                      commons-beanutils        commons-io               javax                    oro
avalon-framework         commons-chain            commons-lang             junit                    sslext
backport-util-concurrent commons-cli              commons-logging          log4j                    xerces
ch                       commons-codec            commons-validator        logkit 

# Plugin Repository

<pluginRepository>에는 Maven 플러그인을 다운받을 수 있는 저장소를 나열한다.

<project>
    <pluginRepositories>
        <pluginRepository>
            <id>acme corp</id>
            <name>Acme Internal Corporate Repository</name>
            <url>http://acmecorp.com/plugins</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
            <releases>
                <enabled>false</enabled>
            </releases>
        </pluginRepository>
    </pluginRepositories>
</project>

# distributionManagement 태그

deploy goal을 실행했을 때 배포되는 위치를 기술한다.

<project>
<distributionManagement>
    <repository>
        <id>releases-repo</id>
        <name>Releases Repository</name>
        <url>일반적인 회사 내부 repository url</url>
    </repository>
    <snapshotRepository>
        <id>snapshots-repo</id>
        <name>Snapshots Repository</name>
        <url>일반적인 회사 내부 repository url</url>
    </snapshotRepository>
</distributionManagement>s
</project>

# Super pom.xml

Maven 프로젝트의 모든 pom.xml은 사전에 정의된 Super pom.xml을 암시적으로 상속한다. Super pom.xml에는 사전에 합리적으로 정의한 환경설정이 포함되어있다. 프로젝트의 pom.xml은 이 Super pom.xml을 암시적으로 상속하기 때문에 모든 환경설정을 번거롭게 구성할 필요가 없다.

이처럼 사전에 합리적으로 정의된 환경설정을 제공하여 환경설정 비용을 줄이는 것을 설정보다 관습(CoC, Convention over Configuration)이라고 한다.

Super pom.xml내용은 다음과 같다.

<project>
  <modelVersion>4.0.0</modelVersion>

  <repositories>
    <repository>
      <id>central</id>
      <name>Central Repository</name>
      <url>http://repo.maven.apache.org/maven2</url>
      <layout>default</layout>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
  </repositories>

  <pluginRepositories>
    <pluginRepository>
      <id>central</id>
      <name>Central Repository</name>
      <url>http://repo.maven.apache.org/maven2</url>
      <layout>default</layout>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
      <releases>
        <updatePolicy>never</updatePolicy>
      </releases>
    </pluginRepository>
  </pluginRepositories>

  <build>
    <directory>${project.basedir}/target</directory>
    <outputDirectory>${project.build.directory}/classes</outputDirectory>
    <finalName>${project.artifactId}-${project.version}</finalName>
    <testOutputDirectory>${project.build.directory}/test-classes</testOutputDirectory>
    <sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
    <scriptSourceDirectory>src/main/scripts</scriptSourceDirectory>
    <testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory>
    <resources>
      <resource>
        <directory>${project.basedir}/src/main/resources</directory>
      </resource>
    </resources>
    <testResources>
      <testResource>
        <directory>${project.basedir}/src/test/resources</directory>
      </testResource>
    </testResources>
    <pluginManagement>
      <!-- NOTE: These plugins will be removed from future versions of the super POM -->
      <!-- They are kept for the moment as they are very unlikely to conflict with lifecycle mappings (MNG-4453) -->
      <plugins>
        <plugin>
          <artifactId>maven-antrun-plugin</artifactId>
          <version>1.3</version>
        </plugin>
        <plugin>
          <artifactId>maven-assembly-plugin</artifactId>
          <version>2.2-beta-5</version>
        </plugin>
        <plugin>
          <artifactId>maven-dependency-plugin</artifactId>
          <version>2.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-release-plugin</artifactId>
          <version>2.0</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>

  <reporting>
    <outputDirectory>${project.build.directory}/site</outputDirectory>
  </reporting>

  <profiles>
    <!-- NOTE: The release profile will be removed from future versions of the super POM -->
    <profile>
      <id>release-profile</id>

      <activation>
        <property>
          <name>performRelease</name>
          <value>true</value>
        </property>
      </activation>

      <build>
        <plugins>
          <plugin>
            <inherited>true</inherited>
            <artifactId>maven-source-plugin</artifactId>
            <executions>
              <execution>
                <id>attach-sources</id>
                <goals>
                  <goal>jar</goal>
                </goals>
              </execution>
            </executions>
          </plugin>
          <plugin>
            <inherited>true</inherited>
            <artifactId>maven-javadoc-plugin</artifactId>
            <executions>
              <execution>
                <id>attach-javadocs</id>
                <goals>
                  <goal>jar</goal>
                </goals>
              </execution>
            </executions>
          </plugin>
          <plugin>
            <inherited>true</inherited>
            <artifactId>maven-deploy-plugin</artifactId>
            <configuration>
              <updateReleaseInfo>true</updateReleaseInfo>
            </configuration>
          </plugin>
        </plugins>
      </build>
    </profile>
  </profiles>

</project>

Eclipse 환경에서 프로젝트의 pom.xml 파일을 오픈한 후 Effective POM 탭을 확인할 수 있다.

Effective POM은 Super pom과 프로젝트의 pom.xml을 병합하여 프로젝트에 최종 적용되는 pom.xml이다.