Maven POM.xml으로 의존성과 빌드 구성 관리하기
Maven POM.xml의 좌표, 의존성 스코프와 충돌 해결, 프로파일, 부모 POM, 멀티 모듈 빌드 구성을 정리한다.
2026-08-14 · 최초 발행 2025-06-28
Maven 프로젝트의 규칙은 POM.xml에 모인다
POM(Project Object Model)은 Maven이 프로젝트를 구성하고 빌드하는 방법을 읽는 XML 파일이다. 프로젝트의 의존성, 빌드 설정, 플러그인, 모듈 관계를 선언하며, Maven 기반 프로젝트에서는 이 파일이 구조의 기준점이 된다.
가장 단순한 POM은 다음과 같다.
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 기타 설정 요소들 -->
</project>
modelVersion은 POM 모델 버전이며 현재 표준은 4.0.0이다. groupId는 보통 조직 도메인을 역순으로 표현한 그룹 식별자이고, artifactId는 빌드 결과물을 가리킨다. version은 프로젝트 버전으로, 릴리스에는 1.0, 개발 중인 결과물에는 1.0-SNAPSHOT 같은 표기를 사용할 수 있다.
groupId, artifactId, version은 Maven 저장소 안에서 결과물을 고유하게 식별하는 좌표다.
프로젝트 목적에 따라 packaging, name, description, url도 추가할 수 있다. packaging은 jar, war, ear 등의 패키징 방식을 정하며 기본값은 jar다. 이 밖에 properties, dependencies, build가 프로젝트 전반의 설정을 담는다.
선언한 의존성으로 라이브러리 관계를 관리한다
POM에 의존성을 적어두면 Maven이 필요한 라이브러리를 내려받아 프로젝트에 포함한다.
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.9</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
의존성 스코프는 라이브러리가 어느 단계에 필요한지 지정한다. compile은 기본값으로 컴파일과 런타임에 포함된다. provided는 컴파일에는 필요하지만 런타임에는 외부가 제공하는 경우에 사용하며, 서블릿 API가 예다. runtime은 JDBC 드라이버처럼 컴파일 시점에는 필요 없고 실행 시점에 필요한 의존성이다. test는 JUnit처럼 테스트 컴파일과 실행에만 사용한다.
system은 provided와 비슷하지만 Maven 중앙 저장소가 아닌 명시적 경로에서 JAR 파일을 제공받는다. import는 다른 POM의 의존성 관리 섹션을 가져올 때 쓴다.
직접 선언한 라이브러리가 다시 필요로 하는 라이브러리도 Maven은 전이 의존성으로 가져온다. 이 동작 덕분에 프로젝트가 의존하는 전체 라이브러리 관계를 직접 모두 나열하지 않아도 된다.
같은 라이브러리의 다른 버전이 경로에 등장하면 Maven은 의존성 트리에서 더 가까운 버전을 선택한다. 거리가 같으면 pom.xml에 먼저 선언된 의존성의 버전을 택한다. 특정 전이 의존성을 제외해야 할 때는 다음처럼 선언한다.
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.9</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
값과 빌드 규칙을 한곳에서 다루기
반복되는 버전이나 설정값은 properties로 정의해 참조할 수 있다. 버전 변경 지점을 모을 수 있다는 점에서 의존성 선언이 많은 프로젝트에 유용하다.
<properties>
<java.version>11</java.version>
<spring.version>5.3.9</spring.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
build 섹션은 소스와 리소스의 위치, 사용할 플러그인 등 빌드 과정의 규칙을 정한다.
<build>
<sourceDirectory>src/main/java</sourceDirectory>
<testSourceDirectory>src/test/java</testSourceDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
환경 차이는 프로파일로 분리한다
개발, 테스트, 운영처럼 환경마다 값이 달라질 때는 프로파일을 사용한다. 활성화된 프로파일에 따라 같은 POM에서 다른 설정을 적용할 수 있다.
<profiles>
<profile>
<id>development</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<db.url>jdbc:mysql://localhost:3306/devdb</db.url>
</properties>
</profile>
<profile>
<id>production</id>
<properties>
<db.url>jdbc:mysql://prod-server:3306/proddb</db.url>
</properties>
</profile>
</profiles>
운영 프로파일은 다음 명령으로 활성화한다.
mvn clean install -Pproduction
부모 POM으로 공통 정책을 물려준다
프로젝트 규모가 커지면 공통 설정을 부모 POM에 두고 하위 프로젝트가 상속하도록 구성할 수 있다. 자식 POM은 부모에서 groupId와 version을 상속받는다.
<!-- 자식 pom.xml -->
<project>
<parent>
<groupId>com.example</groupId>
<artifactId>parent-project</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>child-module</artifactId>
<!-- 부모에서 groupId와 version을 상속받음 -->
</project>
하나의 큰 프로젝트를 여러 모듈로 나눌 때는 부모 POM의 modules에 하위 모듈을 등록한다.
<!-- 부모 pom.xml -->
<project>
<groupId>com.example</groupId>
<artifactId>parent-project</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<modules>
<module>module-core</module>
<module>module-web</module>
<module>module-api</module>
</modules>
</project>
의존성 버전을 중앙에서 다뤄야 한다면 dependencyManagement를 사용할 수 있다. 관리 섹션에서 버전을 정하면 하위 의존성 선언에서는 버전을 생략할 수 있다.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>5.3.9</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- 버전을 명시하지 않아도 위에서 관리되는 버전 사용 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
</dependencies>
라이프사이클 단계는 POM 설정을 따라 실행된다
Maven은 validate부터 deploy까지 이어지는 라이프사이클을 제공한다. 각 단계에서 실행되는 플러그인과 설정은 POM에 정의된 내용을 따른다.
Spring Boot와 마이크로서비스 구성에서의 POM
Spring Boot 프로젝트는 일반적으로 spring-boot-starter-parent를 상속한다.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.4</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
이 구성에서는 Spring Boot의 의존성 관리 기능을 통해 호환되는 라이브러리 버전을 선택해 사용할 수 있다.
마이크로서비스 아키텍처에서는 공통 부모 POM을 두고 서비스별 모듈이 이를 상속하는 형태를 자주 사용한다.
이때 parent-pom은 모든 마이크로서비스가 공유하는 의존성과 플러그인을 정의한다. 각 서비스는 공통 정책을 상속한 뒤 자신에게 필요한 의존성만 추가한다.