[maven] maven을 활용한 의존성 관리
- -
이번 포스트에서는 maven을 이용한 프로젝트 관리에 대해서 살펴본다.
Maven이란?
Maven은 아파치 재단에서 관리하는 소프트웨어 프로젝트 관리 도구로 POM이라는 개념을 기반으로한다. 여기서 POM(Project Object Model: 프로젝트 객체 모델)이란 프로젝트의 구성요소, 빌드 설정, 의존성 관리 등을 XML 파일 형태(pom.xml)로 정의하며 이를 통해 프로젝트의 컴파일 이나 테스트 실행 시에 필요한 라이브러리 및 플러그인을 관리하는 것을말한다.
또한 Maven은 프로젝트의 구조를 강제해서 다양한 개발 환경(OS, IDE 등)에서 동일한 개발 환경을 구축할 수 있다. 이는 프로젝트의 이식성과 호환성 향상에 큰 도움이 된다.
추가적으로 Maven은 다음과 같은 이점을 제공한다.
- Maven Central Repository: 방대한 라이브러리 저장소를 통해 필요한 의존성을 쉽게 찾아 사용할 수 있다. 이를 통해 프로젝트 설정 시간을 대폭 줄여주며 의존성 관리를 간소화 한다.
- 빌드 생명 주기 관리: 표준화된 빌드 생명주기를 제공하여 개발자가 빌드 프로세스를 명확히 이해하고 관리할 수 있게 한다.
프로젝트 구조
다음은 maven 기반의 프로젝트를 생성했을 때 기본적으로 구성되는 구조이다.
경로 | 설명 |
src/main/java | Application/Library sources |
src/main/resources | Application/Library resources |
src/main/filters | Resource filter files |
src/main/webapp | Web application sources |
src/test/java | Test sources |
src/test/resources | Test resources |
src/test/filters | Test resource filter files |
src/it | Integration Tests (primarily for plugins) |
src/assembly | Assembly descriptors |
src/site | Site |
LICENSE.txt | Project's license |
NOTICE.txt | Notices and attributions required by libraries that the project depends on |
README.txt | Project's readme |
[출처: https://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html]
프로젝트들이 공통적으로 이런 구조를 가진다면 어떤 OS에서 어떤 IDE를 이용해서 개발하던간에 통일된 환경에서 작업이 가능하다.
pom.xml과 의존성 관리
프로젝트를 하다 보면 프로젝트의 구성에 대해서 공유하면서 싱크를 맞춰야 할 정보들이 많다. 이런 정보들이 필요할 때마다 매번 물어가며 프로젝트를 진행하기는 너무 힘들다.
POM 기반의 maven은 pom.xml 파일에 프로젝트에서 필요한 모든 내용을 담는다. 따라서 pom.xml만 배포되면 어떤 프로젝트를 어떤 플랫폼에서 어떤 IDE로 하더라도 동일한 환경이 된다.
다음은 스프링 부트에서 사용되는 pom.xml 파일의 예이다.
다음은 pom.xml의 주요 속성들이다.
- modelVersion : POM model의 버전으로 현재는 4.0.0으로 고정
- parent : 상위 프로젝트에 대한 정보로 상위 프로젝트의 내용을 현재 프로젝트에서 상속해 사용
- groupId : 프로젝트를 생성하는 회사(조직)의 아이디로 일반적으로 도메인 이름을 거꾸로 사용
- artifactId : 프로젝트 이름 성격으로 groupId 내에서 유일해야 함
- 일반적으로 group id와 artifact id를 연결해서 기본 패키지 이름 구성
- 어떤 경우는 group id가 기본 패키지가 되고 artifact id는 빌드 파일의 이름이 됨
- version : 프로젝트의 현재 버전으로 프로젝트 개발 중일 때는 SNAPSHOT을 접미사로 사용.
- packaging : 배포 파일의 패키징 유형(jar, war)
- name : 프로젝트, 프로젝트 이름
- properties : pom.xml에서 사용할 속성 선언을 선언. 주로 라이브러리의 버전을 한 군데서 관리하기 위함
- dependencies : 프로젝트와 의존 관계에 있는 라이브러리들을 관리
물론 이 외에도 많은 속성들이 있는데 전체 내용은 아래를 참조하자.
Maven – POM Reference (apache.org)
의존성(라이브러리) 관리
그럼 Maven은 어떤 방식으로 프로젝트에서 필요한 라이브러리를 관리하고 배포해주는 것일까?
Maven은 중앙 저장소(Central Repository: https://repo.maven.apache.org/maven2/)라는 곳에 관리하는 라이브러리들에 대한 정보가 등록돼 있다. 저장소에 등록된 라이브러리들은 group id, artifact id, version 등의 정보가 함께 저장되는데 각각 다음의 의미를 갖는다.
- group id: 프로젝트를 생성하는 조직을 구분할 수 있는 구분자로 일반적으로 java의 package naming rule을 따라 도메인을 거꾸로 사용한다.
- artifactid: 프로젝트의 이름으로 일반적으로 배포될 때 사용되는 jar 파일에서 version 정보가 빠진 내용이다.
- version: '.'로 구분되는 버전 정보 (1.0, 2.0.1, ...)로 메이저.마이너.패치 버전을 의미한다.
- scope: 해당 의존성을 언제, 어떻게 클래스 패스에 추가해서 사용할 것인가를 결정한다.
Central Repository에 있는 라이브러리를 편리하게 검색하는 서비스를 제공하는 사이트들이 여럿 있는데 그중 대표적인 곳으로 https://mvnrepository.com이 있다.
위 사이트에서 필요한 라이브러리를 검색하면 아래와 같은 xml 태그를 얻을 수 있는데 이 정보를 pom.xml의 <dependencies>에 추가해주면 중앙 저장소에 저장되어있는 라이브러리를 다운로드 해서 로컬 레포지터리에 저장하고 사용할 수 있게 해준다.
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
그런데 기존에 작성된 의존성들을 유심히 살펴보면 <version>에 대한 정보가 없는것을 확인할 수 있다.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
이것도 SpringBoot의 편리한 점 중에 하나인데 우리가 프로젝트를 하다 보면 라이브러리간 호환성 때문에 곤란한 경우가 왕왕 발생한다. SpringBoot에서는 자주 사용되는 라이브러리에 대해서 SpringBoot와 호환되는 라이브러리를 선별해서 등록해 두었다. 따라서 SpringBoot에서 관리하는 라이브러리에 대해서는 <version>을 생략하는 것이 오히려 안정성에 도움을 준다. 물론 이 세상의 모든 라이브러리를 관리하는 것은 아니니 일단 한번 지워보고 오류가 나면 복원시켜주자.
dependency의 scope
scope의 용도는 해당 의존성을 언제, 어떻게 클래스 패스에 넣어서 사용할 것인가를 결정하는 것이다.
- compile: 기본 범위로 생략 시 적용되며 컴파일과 런타임에 모두 사용 가능하다.
- provided: 컴파일과 테스트시에는 사용되지만 런타임에는 외부 환경에서 제공되는 것을 사용한다. 예를 들어 운전 연습을 할 때에는 연습용 차를 사용하지만 막상 시험 볼 때는 시험장의 차를 사용하는 케이스이다. 웹 프로그래밍을 하려면 Servlet API를 사용하는데 런타임에는 WAS(tomcat)가 이를 제공하기 때문에 packaging 과정에서 제외하려면 provided로 설정한다.
- runtime: 컴파일 시에는 불필요하고 실행 시에만 필요한 경우로 런타임이나 테스트 시는 classpath에 포함되지만 컴파일 시에는 포함되지 않는다. JDBC 드라이버 등이 이에 해당한다.
- test: 테스트 진행 시에만 사용되고 배포 시에는 제외되며 따라서 main 영역에서는 사용되지 않는다.
- system: 로컬 시스템에 설치된 JAR 파일처럼 외부에서 제공되는 의존성을 참조하는 경우에 사용한다.
예를 들어 json 문자열을 만들기 위한 jackson-databind는 언제나 사용되기 때문에 <scope>가 생략된 compile이 적용된다.
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.2.2</version>
</dependency>
junit은 테스트에서만 필요하기 때문에 scope가 test로 설정된다. 이 경우는 src/test 영역에서만 사용 가능하고 src/main에서는 사용할 수 없다.
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
plugin
maven을 이용해서 어떤 추가적인 동작을 수행하기 위해서 플러그인을 지원한다. 플러그인은 <dependencies> 아래에 <build> 내에 <plugins> 내부에 작성한다.
<build>
<plugins>
<plugin>
...
</plugin>
<plugin>
...
</plugin>
</plugins>
</build>
대표적인 플러그인들에 대해 살펴보자.
Maven – Available Plugins (apache.org)
compiler plugin
properties에 jdk 버전을 설정했던 것과 유사한데 보다 상세한 설정들이 가능하다.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<configuration>
<encoding>utf-8</encoding>
<compilerArgument>-Xlint:all</compilerArgument>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
jar plugin
jar로 패키징 된 파일을 바로 실행하기 위해서 Manifest file을 생성해 주는 plugin으로 main 메서드가 있는 클래스를 바로 실행할 수 있다. (일부 버전은 Unknown error 가 발생하므로 테스트해 가며 사용할 것)
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.1</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.example.HelloMain</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
의존사항들을 포함한 jar 배포
pom.xml에 등록된 의존사항들을 포함해서 jar를 만들기 위해서는 maven-assembly-plugin을 사용하면 된다.
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.andy.labgen.ui.LabGeneratorUi</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
'tools & libs > 빌드툴(maven,gradle)' 카테고리의 다른 글
[maven] maven trouble shooting (0) | 2022.04.12 |
---|---|
[maven] maven lief cycle 관리 (0) | 2022.04.12 |
[maven]서버에 배포하기 (0) | 2021.08.22 |
[gradle]build.gradle (0) | 2021.01.30 |
[gradle]gradle을 위한 살짝 Groovy (0) | 2021.01.30 |
소중한 공감 감사합니다