반응형

Maven은 다양한 라이브러리를 관리한다. 물론 직접 라이브러리를 만들고 Maven으로 관리 할 수도 있다. 그 기본에 대해 설명한다.


자체 라이브러리 프로젝트 생성

Maven은 중앙 저장소에서 라이브러리를 자동으로 다운로드하여 사용할 수 있다. 그럼 이용할 수 있는 것은 중앙 저장소에 등록되어 있는 것 뿐인가? 라는 의문이 생긴다.

그러나 그렇지는 않다. 직접 만든 라이브러리를 프로젝트에서 참조하여 이용하는 것도 물론 가능하다.

라이브러리 프로젝트 생성

그러면 실제로 간단한 라이브러리를 만들고, 그것을 이용하여 보자. 여기에서는 예로서 "mylib"라는 라이브러리 프로젝트를 만들려고 한다. 다음과 같이 명령을 실행하고 Project의 설정 정보를 입력하여 생성한다.

Project 생성 명령

$ mvn archetype:generate -DarchetypeArtifactId=maven-archetype-quickstart

입력 정보

  • 그룹 ID : com.devkuma.mylib
  • 아티팩트 ID : MyLib
  • 버전 : 1.0-SNAPSHOT: :( 기본 상태)
  • 패키지 : com.devkuma.mylib: :( 기본 상태)

프로젝트가 생성되면, 여기에 간단한 처리를 위한 클래스를 추가하고 라이브러리로 사용하려고 한다.

템플릿으로 maven-archetype-quickstart를 지정하였기, 이 프로젝트는 매우 일반적인 Java 응용 프로그램 프로젝트이다. 라이브러리에 뭔가 특별한 것이 있는 것은 아니다.

MyLib.java 생성

기본적으로 App.java라는 클래스가 준비되어 있지만, 이것은 응용 프로그램으로 사용 메인 클래스로 이용하기로 한다. 이와는 별도로 라이브러리용 클래스를 만든다.

Project 안에 /src/main/java/com/devkuma/mylib/ 폴더 안에 "MyLib.java"라는 이름으로 Java 소스 코드 파일을 만든다. 그리고 아래와 같이 작성한다.

package com.devkuma.mylib;
 
import java.util.*;
 
public class MyLib {
    private List<Integer> data = new ArrayList<Integer>();
 
    public MyLib(Integer...n){
        super();
        data = Arrays.asList(n);
    }
 
    public void add(int n){
        data.add(n);
    }
 
    public int getTotal(){
        int num = 0;
        for(int n:data){
            num += n;
        }
        return num;
    }
 
    @Override
    public String toString(){
        String res = "{data:[";
        for(int n:data){
            res += n + ", ";
        }
        res += "]}";
        return res;
    }
}

여기에는 몇 가지 정수를 List에 모와서 그 합계를 표시하는 메소드을 제공하고 있다. 평범하지만 라이브러리의 동작을 확인하는 정도의 수준으로 충분하다.

pom.xml은 일단 기본 상태로 그대로 유지하고, 라이브러리이라고 해도 프로젝트 자체는 당연한 Java 어플리케이션이기 때문에 특별한 것은 필요없다.

App.java 수정

만든 MyLib 클래스를 실제로 사용해 보자. 기본적으로 제공되는 App.java을 열고 아래와 같이 소스 코드를 작성한다. 그리고 빌드하고 응용 프로그램을 실행 해 봅니다.

package com.devkuma.mylib;
 
public class App {
 
    public static void main( String[] args )    {
        MyLib lib = new MyLib(10, 20, 30, 40);
        System.out.println("MyLib " + lib);
        System.out.println("total " + lib.getTotal());
    }
}

패키지 생성

$ mvn package

패키지를 사용하여 App 클래스 실행

$ java -classpath target\MyLib-1.0-SNAPSHOT.jar com.devkuma.mylib.App

실행하면 다음과 같이 콘솔에 출력된다. App 클래스에서 MyLib 클래스를 생성하여 이용한 결과이다.

MyLib {data : 10, 20, 30, 40,]}
total 100

우선 MyLib의 기능이 잘 동작하고 있는 것을 확인하였다.

로컬 저장소 설치

이것으로 패키지가 완성은 되지만, 이대로 MyLib 다른 프로젝트에서 사용할 수 없다. 왜냐하면 이용하려고 해도 저장소에 MyLib가 준비되어 있지 않기 때문이다.

저장소라는 것은 라이브러리가 등록되어 있는 곳이다. 이것은 중앙 저장소가 가장 널리 사용되고 있지만,이 외에도 로컬 환경에도 저장소는 준비되어 있다. 이를 "로컬 저장소"라고 한다.

로컬 저장소는 사용자 폴더에 .m2 폴더명으로 위치한다.

/Users/{사용자 폴더}/.m2

직접 만든 라이브러리를 사용해야 경우는 이 로컬 저장소에 라이브러리를 추가하면, 그것을 다른 프로젝트에서 참조하고 사용할 수 있다. 여기에는 다음과 같이 실행한다.

$ mvn install

이 명령은 로컬 저장소에 패키지를 설치하는 것이다. 이것으로 MyLib가 로컬 저장소에 추가되고, 다른 프로젝트에서 참조할 수 있게 되었다.

SampleMavenApp에서 사용

생성한 MyLib을 다른 프로그램에서 사용해 보자. 지금까지 샘플로 사용한 SampleMavenApp 프로젝트 중에서 이용해 보기로 한다. 아래에 App.java 샘플 코드를 올려 두었다.

package com.devkuma;
 
import com.devkuma.MyLib;
 
public class App {
     
    public static void main( String[] args ){
        MyLib lib = new MyLib(123, 456, 78, 90);
        System.out.println("total " + lib.getTotal());
        System.out.println(lib);
    }
}

SampleMavenApp 내에서 MyLib를 이용하기 위해서는, MyLib를 의존 라이브러리로 프로젝트에 등록 한다. 이것은 pom.xml의 <dependencies> 태그 내에 MyLib 설정을 추가하면 된다.

<dependency>
    <groupId>com.devkuma.mylib</groupId>
    <artifactId>MyLib</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

이것이 MyLib의 <dependency> 태그이다. 이 태그를 pom.xml의 <depdendencies>에 추가한다.

동작 확인

그럼 프로그램이 제대로 작동하는지 확인한다. 먼저 응용 프로그램을 패키지한다.

$ mvn package

이것으로 Jar 파일이 생성되었고, 이어서 프로그램을 실행하여 동작을 확인해 본다.

mvn exec:java

SampleMavenApp에는 exec-maven-plugin 플러그인의 설정을 작성하였기에, exec:java으로 App 클래스를 실행할 수 있다. (자세한 내용은 Java 응용 프로그램 개발을 참조)

이것으로 일단은 외부 라이브러리를 사용할 수 있게 되었다. 이도 아직 완벽하지 않다. 일반적으로 java 명령을 사용하여 실행하자.

$ java -classpath target\SampleMavenApp-1.0.jar com.devkuma.App

이것으로 프로그램이 실행되지 않고 에러가 발생한다. 이는 도대체 왜 일까? java 커멘드로 수행할 수 없는 것인가. 그 이유는 라이브러리가 들어 있지 않기 때문이다.

mvn package으로 target 에 저장되는 Jar 파일에는 사실 MyLib의 클래스는 포함되지 않다. 이 SampleMavenApp 프로젝트의 클래스만 있을 뿐이다. exec:java으로 수행할 수 있었던 것은 로컬 저장소에 있는 라이브러리를 참조하도록 되어 있었기 때문이다.

그에 비해 일반적인 java 명령은 로컬 저장소를 참조하지 않는다. 그래서 MyLib의 Jar 파일을 Java와 JDK의 lib 폴더에 복사해야 사용할 수 있다.

더 확실한 것은 MyLib도 함께 Jar 파일에 포함시키는 것이다. 포함 시키는 방법은 maven-assembly-plugin를 참조하길 바란다.



maven-assembly-plugin 의존 라이브러리 포함

의존 라이브러리를 포함시키기

패키지를 할시에 의존 라이브러리로 Jar 파일에 포함하여 저장 시킬 수 있는데, 이는 maven-assembly-plugin이라는 플러그인을 설정하면 할 수 있다. 아래에 종속 라이브러리를 포함하여 Jar 파일에 저장하기 위한 설정을 올려 두었다.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <version>3.1.0</version>
    <configuration>
        <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
    </configuration>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>single</goal>
            </goals>
        </execution>
    </executions>
</plugin>

<configuration> 태그에 대해

설정 정보를 기술하는 <configuration>는 <descriptorRefs>라는 태그를 제공하고, 나아가 그 안에 <descriptorRef>라는 태그를 준비하고 있다. 여기에 jar-with-dependencies로 지정하여 Jar의 일체화를 위한 설정임을 지정할 수 있다.

그 후에 <executions>에 있는 <execution>에 필요한 설정을 한다. <phase>으로 package 를 <goals>의 <goal>으로 single 을 각각 지정하고 있는데, 이는 패키징을 할때 1개의 Jar 파일로 정리하도록 하는 것이다. Jar 파일명은 SampleMavenApp-1.0-jar-with-dependencies.jar과 같이 -jar-with-dependencies가 붙여진다.

이 플러그인 설정을 pom.xml에 추가하여, 다시 mvn package하여 패키지를 해보자. 그리고 다시 java 커멘드로 Jar 파일을 실행해 본다.

$ java -classpath target\SampleMavenApp-1.0-jar-with-dependencies.ja com.devkuma.App

이번에는 제대로 프로그램이 실행될 것이다. Jar 파일에 MyLib이 포함되기 때문이다. 생성된 Jar 파일은 다른 컴퓨터에 복사하고 실행하여도 문제없이 동작한다.

SampleMavenApp의 완성된 pom.xml

SampleMavenApp의 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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.devkuma</groupId>
  <artifactId>SampleMavenApp</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>SampleMavenApp</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
     <dependency>
       <groupId>com.devkuma.mylib</groupId>
       <artifactId>MyLib</artifactId>
       <version>1.0-SNAPSHOT</version>
     </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>1.6.0</version>
        <configuration>
          <mainClass>com.devkuma.App</mainClass>
        </configuration>
      </plugin>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <version>3.0.2</version>
        <configuration>
          <archive>
            <manifest>
                <mainClass>com.devkuma.App</mainClass>
                <addClasspath>true</addClasspath>
                <addExtensions>true</addExtensions>
                <packageName>com.devkuma</packageName>
            </manifest>
          </archive>
        </configuration>
      </plugin>
    
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>3.1.0</version>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
        <executions>
           <execution>
             <phase>package</phase>
             <goals>
               <goal>single</goal>
             </goals>
          </execution>
        </executions>
      </plugin>
            
    </plugins>
  </build>

</project>

이번 했던 작업에서 알 수 있듯이, 자체 라이브러리의 사용은 라이브러리 자체에 아무것도 특별한 작업은 필요없다. 유일하게 mvn install 명령으로 라이브러리를 로컬 저장소에 설치할 뿐이다.

최대의 포인트는 라이브러리를 이용하는 프로젝트에 있다. 먼저 <dependency> 태그 라이브러리를 추가하는 것이 필수 사항이다. 이것으로 exec:java라면 수행할 수 있다.

의존 라이브러리까지 모든 1개의 Jar에 정리하는 exec-assembly-plugin 플러그인 설정을 추가한다. 이는 프로젝트에 고유의 설정 등은 없기에, 여기에 게재한 태그를 그대로 복사해서 붙여 넣기하여 사용하면 될 것이다.

반응형

+ Recent posts