메이븐으로 자바 개발

아래 글은 http://spring.io/guides/gs/maven/를 번역한 것입니다.

메이븐 설치

  1. http://maven.apache.org/download.cgi에서 최신 바이너리 파일을 다운로드한다.
  2. 압축을 풀고 생성된 디렉터리를 원하는 곳에 옮긴다.(예, C:\Program Files\apache-maven-3.8.7)
  3. 메이븐 bin 디렉터리를 Path에 추가한다.
  4. JAVA_HOME 환경 변수가 있는지 확인한다. 메이븐은 JAVA_HOME 환경 변수를 참조하기에 없다면 만들어야 한다. (JDK 설치 문서 참조)

명령 프롬프트에서 다음 명령으로 메이븐 버전을 확인한다.

C:\ Command Prompt
C:\Users\kim> mvn -v
Apache Maven 3.8.7
Maven home: C:\Program Files\apache-maven-3.8.7\bin\..
Java version: 17.0.2, vendor: Oracle Corporation
Java home: C:\Program Files\Java\jdk-17.0.2\jre
..

메이븐 프로젝트 생성

pom.xml 파일의 내용과 메이븐 프로젝트 디렉터리 구조를 안다면 메이븐 프로젝트를 만들 수 있다.

HelloWorld를 프로젝트 루트 디렉터리라면,
HelloWorld 아래에 서브 디렉터리 src\main\java를 만든다.
src\main\java은 메이븐 프로젝트에서 자바 소스 파일을 두는 디렉터리다.
(아래에서 맨 끝단의 hello는 생성할 자바 클래스의 패키지 이름)

HelloWorld (project root directory)
   └── src
        └── main
             └── java
                  └── hello

프로젝트 루트에 pom.xml 파일을 작성한다.

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
                             http://maven.apache.org/maven-v4_0_0.xsd">
                       
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.springframework.gs</groupId>
  <artifactId>quick-start</artifactId>
  <version>0.1.0</version>
  <packaging>jar</packaging>
  
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
  </properties>
  
</project>
  • <modelVersion> - POM model version으로 언제나 4.0.0
  • <groupId> - 프로젝트의 소유자인 조직이나 기관으로 패키지 형식의 이름을 가진다.
  • <artifactId> - 프로젝트 이름. 생성되는 jar나 war 파일에 이 이름이 붙여진다.
  • <version> - 프로젝트 버전
  • <packaging> - 프로젝트를 어떻게 패키지 할 것인가를 설정한다. 디폴트는 jar이고 웹 애플리케이션이면 war로 설정한다.

hello 디렉터리에 다음 두 개의 자바 소스 파일을 작성한다.

src/main/java/hello/HelloWorld.java

HelloWorld.java
package hello;

public class HelloWorld {
  public static void main(String[] args) {
    Greeter greeter = new Greeter();
    System.out.println(greeter.sayHello());
  }
}

src/main/java/hello/Greeter.java

Greeter.java
package hello;

public class Greeter {
  public String sayHello() {
    return "Hello world!";
  }
}

메이븐 명령어

다음 명령어를 pom.xml 파일이 있는 위치(프로젝트 루트 디렉터리)에서 실행한다.

mvn compile

mvn compile은 컴파일을 실행한다.
컴파일 결과물이 target/classes 폴더에 생성된다.
target/classes 폴더는 컴파일이 수행되면서 만들어진다.
mvn compile

mvn package

mvn package는, 자바 코드를 컴파일하고, 테스트를 수행하고, 컴파일 결과물을 패키지(jar 또는 war)로 묶어서 target 디렉터리에 저장한다.
pom.xml 내용대로, gs-maven-initial-0.1.0.jar 파일이 target 디렉터리에 생성된다.
mvn package

mvn install

mvn install은 패키징된 jar 파일을 로컬 저장소에 저장한다.
mvn install

mvn clean

mvn clean은 빌드를 통해 생성된 모든 산출물을 삭제한다.
mvn clean

compile, package, install, clean을 goal이란 하는데, goal을 중복해서 수행할 수 있다.

mvn clean compile

다음은 HelloWorld 메이븐 프로그램을 실행하는 명령이다.

mvn exec:java -Dexec.mainClass=hello.HelloWorld

의존성 추가

대부분의 애플리케이션은 외부 라이브러리에 의존한다.
예제도 외부 라이브러리를 사용하도록, HelloWorld.java를 수정한다.

src/main/java/hello/HelloWorld.java

HelloWorld.java
package hello;

import org.joda.time.LocalTime;

public class HelloWorld {
  public static void main(String[] args) {
    LocalTime currentTime = new LocalTime();
    System.out.println("The current local time is: " + currentTime);

    Greeter greeter = new Greeter();
    System.out.println(greeter.sayHello());
  }
}

mvn compile을 실행하면 실패한다.
의존성을 추가하지 않았기 때문이다.
pom.xml 파일을 열고 아래와 같이 의존성을 추가한다.

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
                             http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>org.springframework.gs</groupId>
    <artifactId>gs-maven-initial</artifactId>
    <version>0.1.0</version>
    <packaging>jar</packaging>
    
  <dependencies>
    <!-- https://mvnrepository.com/artifact/joda-time/joda-time -->
    <dependency>
      <groupId>joda-time</groupId>
      <artifactId>joda-time</artifactId>
      <version>2.12.2</version>
    </dependency>
  </dependencies>
  
</project>

dependency의 하위 엘리먼트 scope은 대부분 생략한다.--생략하면 디폴트 값이 적용된다--
scope 엘리먼트는 compile(디폴트), provided 또는 test 중 하나를 값으로 갖는다.

  • provided: 컴파일할 때 필요하지만 런타임에는 컨테이너에 의해 제공되는 것.(예, Servlet API)
  • test: 컴파일하고 테스트에는 필요하지만 빌드(컴파일과 배포)하거나 실행할 때는 필요 없는 것.

의존성을 추가한 후 mvn compile을 실행하면 성공한다.

mvn archetype:generate

mvn archetype:generate를 사용하면 대화형으로 다양한 메이븐 프로젝트를 생성할 수 있다.
프로트타입에 따라 메이븐 디렉터리와 pom.xml 파일이 생성된다.
원형이라는 사전적 의미를 가지는 아키타입archetype은, 자바에선 프로젝트 프로토타입을 뜻한다.
선택한 워크스페이스 디렉터리에서 다음을 실행한다.

C:\ Command Prompt
mvn archetype:generate

아래 화면에서 엔터를 눌러, 우리가 원하는 maven-archetype-quickstart 아키타입을 선택한다.

C:\ Command Prompt
Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 2005:

아래 화면에서도 엔터를 눌러 아키타입 maven-archetype-quickstart의 최신 버전을 선택한다.

C:\ Command Prompt
Choose org.apache.maven.archetypes:maven-archetype-quickstart version:
1: 1.0-alpha-1
2: 1.0-alpha-2
3: 1.0-alpha-3
4: 1.0-alpha-4
5: 1.0
6: 1.1
7: 1.3
8: 1.4
Choose a number: 8:

다음 화면에선, groupId와 artifactId만 값을 지정한다.
version과 package는 엔터를 눌러 디폴트 값을 선택한다.

C:\ Command Prompt
Define value for property 'groupId': : org.springframework.gs
Define value for property 'artifactId': : quick-start
Define value for property 'version':  1.0-SNAPSHOT: :
Define value for property 'package':  org.springframework.gs: :

다음 화면에서 엔터를 눌러 빌드를 시작한다.

C:\ Command Prompt
Confirm properties configuration:
groupId: org.springframework.gs
artifactId: quick-start
version: 1.0-SNAPSHOT
package: org.springframework.gs
 Y: :

artifactId 값대로 quick-start 디렉터리가 생성된다.
quick-start 디렉터리에 pom.xml 파일과 메이븐 디렉터리 구조가 만들어 진다.

pom.xml 의존성에 spring-context를 추가한다.
스프링 최신 릴리스 버전 참고: hhttps://spring.io/projects/spring-framework

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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.springframework.gs</groupId>
  <artifactId>quick-start</artifactId>
  <version>1.0-SNAPSHOT</version>
  <name>quick-start</name>
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>6.0.4</version>
    </dependency>
  </dependencies>
  
  <!-- omit -- >

프로젝트가 A 라이브러리에 의존하는데 A는 B 라이브러리에 의존한다면, 의존성에 A만 추가하더라도 A뿐 아니라 B도 저장소에 저장하는 것이 메이븐 의존성 관리 기능이다.

spring-context만 추가하더라도 spring-context가 의존하는 다른 라이브러리 역시 저장소에 저장된다.

MessageService.java, MessagePrinter.java, Application.java 파일을 /hello 폴더에 생성한다.

C:\ Command Prompt
C:\..quick-start\src\main\java\hello> notepad MessageService.java
MessageService.java
package hello;

public interface MessageService {
  String getMessage();
}
C:\ Command Prompt
C:\..quick-start\src\main\java\hello> notepad MessagePrinter.java
MessagePrinter.java
package hello;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MessagePrinter {

  @Autowired
  private MessageService service;

  public void printMessage() {
    System.out.println(this.service.getMessage());
  }
}
C:\ Command Prompt
C:\..quick-start\src\main\java\hello> notepad Application.java
Application.java
package hello;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.*;

@Configuration
@ComponentScan
public class Application {

  @Bean
  MessageService mockMessageService() {
    return new MessageService() {
      public String getMessage() {
        return "Hello World!";
      }
    };
  }

  public static void main(String[] args) {
    ApplicationContext context = 
      new AnnotationConfigApplicationContext(Application.class);
    MessagePrinter printer = context.getBean(MessagePrinter.class);
    printer.printMessage();
  }
}

빌드

C:\ Command Prompt
mvn compile

실행

C:\ Command Prompt
mvn exec:java -Dexec.mainClass=hello.Application

코드상으로는 MessagePrinter는 MessageService는 서로 결합되어 있지 않지만, 스프링 프레임워크가 이들을 묶어준다.

테스트 실행 후, 메이븐의 로컬 저장소에 저장된 어떤 라이브러리가 저장되었는지 확인한다.
--메이븐 로컬 저장소는 사용자 폴더 안의 .m2 폴더다--

C:\ Command Prompt
C:\Users\kim\.m2\repository\org\springframework>dir /w

[spring-aop]  [spring-beans]  [spring-context]  [spring-core]  

[spring-expression]

spring-context가 의존하는 spring-aop, spring-beans, spring-core, spring-expression도 함께 설치된다.

참고