반응형

1. 개요

 이전 글에서 모듈이란 무엇이고 그것들을 어떻게 사용하는지 알아보았다. 이제 우리가 배운 모든 개념들을 보여줄 간단한 프로젝트를 만들어보자. 여기서는 Maven이나 Gradle을 사용하지 않고 커멘드라인을 사용하여 프로젝트를 빌드할 것이다.

 

1.1 프로젝트 설정

 우선 프로젝트 구조를 잡아야한다. 먼저 프로젝트 폴더를 만들어보자.

mkdir module-project
cd module-project

 이것이 전체 프로젝트의 기반이 되는 디렉토리이다. 따라서 여기에 소스 디렉토리, 리소스 파일 등이 추가될 것이다. 이제 모든 모듈들을 저장할 디렉토리도 만들어보자.

mkdir simple-modules

 전체 프로젝트 구조는 아래와 같다.

module-project
|- simple-modules
  |- hello.modules
    |- com
      |- baeldung
        |- modules
          |- hello
  |- main.app
    |- com
      |- baeldung
        |- modules
          |- main

 

1.2 첫번째 모듈

 이제 기본 구조를 갖추었으니 첫 번째 모듈을 추가해 보자.

 simple-modules 디렉토리 아래에 hello.modules라는 새 디렉토리를 만든다. 우리는 모듈 이름을 어떤 것으로든 정할 수 있으나, 패키지 이름 지정 규칙(예: 단어를 구분하는 마침표 등)을 따르도록 한다. 우리가 원한다면 우리의 메인 패키지의 이름을 모듈 이름으로 사용할 수도 있지만, 우리는 보통 우리가 이 모듈의 JAR을 만들기 위해 사용하는 것과 같은 이름을 쓴다.
 새로운 모듈 아래에서는 원하는 패키지들을 아래와 같이 만들 수 있다.

com.baeldung.modules.hello

 그런 다음 이 패키지에 HelloModules.java라는 새 클래스를 만든다. 코드를 단순하게 유지하도록 한다.

package com.baeldung.modules.hello;

public class HelloModules {
    public static void doSomething() {
        System.out.println("Hello, Modules!");
    }
}

그리고 마침내, hello.modules 루트 디렉토리에 모듈 설명자 파일(module-info.java)을 추가한다.

module hello.modules {
    exports com.baeldung.modules.hello;
}

 

1.3 두번째 모듈

 우리의 첫 번째 모듈은 훌륭하지만, 아무것도 하지 않는다. 이제 우리는 첫 번째 모듈을 사용하는 두 번째 모듈을 만든다.

 simple-modules 디렉토리 아래에 main.app 디렉토리를 만들고 그 안에 모듈 설명자 파일(module-info.java)을 추가한다.

module main.app {
    requires hello.modules;
}

 우리는 어떤 것도 외부에 노출(exports)시킬 필요가 없다. 대신, 우리가 해야 할 일은 우리의 첫 번째 모듈에 의존하는 것이다. 그래서 우리는 그것이 노출(exports)하는 public 클래스에 접근할 수 있다.

 com.baeldung.modules.main 패키지를 만들고 그 안에 MainApp.java라는 새 클래스 파일을 만든다.

package com.baeldung.modules.main;

import com.baeldung.modules.hello.HelloModules;

public class MainApp {
    public static void main(String[] args) {
        HelloModules.doSomething();
    }
}

 이제 다음 단계에서 커멘드 라인을 통해 소스코드를 빌드하고 실행해보자.

 

1.4 모듈 빌드하기

 모듈을 빌드하기 위해서, 간단한 bash 스크립트를 작성하고 그것을 프로젝트 루트에 추가해보자.

 compile-simple-modules.sh라는 파일을 아래와 같이 만들자.

#!/bin/bash
javac -d outDir --module-source-path simple-modules $(find simple-modules -name "*.java")

 이 명령어는 javac, find 두 부분으로 나뉜다. 

 find는 simple-modules 디렉토리 내의 모든 java파일들을 찾는 명령어이다. 이를 통해 자바 파일들의 목록을 직접 자바 컴파일러에게 전달할 수 있다.

 자바 9 이전 버전과 유일하게 다른점은, 모듈을 빌드하기 위해 module-source-path 파라미터를 컴파일러에게 제공해야한다는 것이다.

 이 스크립트를 실행하면, outDir 폴더 내에 두 개의 컴파일된 모듈이 생성된다.

 

1.5 코드 실행하기

 이제 모듈이 정상작동하는지 확인하기 위해 코드를 실행해보자.

 프로젝트 루트에 run-simple-module-app.sh라는 파일을 아래와 같이 만들자.

#!/bin/bash
java --module-path outDir -m main.app/com.baeldung.modules.main.MainApp

 모듈을 실행하기 위해서는, module-path를 메인 클래스에게 제공해야한다. 만약 정상 동작한다면, 아래와 같이 나올 것이다.

$ sh run-simple-module-app.sh 
Hello, Modules!

 

1.6 서비스 추가하기

 이제 모듈을 만드는 방법에 대해 기본적인 이해를 했으니, 좀 더 복잡하게 만들어 보자.

 우리는 'provides…with' 와 'uses' 키워드를 어떻게 사용하는지에 대해 알아볼 것이다.

 먼저 hello.modules 모듈 안에 HelloInterface.java라는 인터페이스를 아래와 같이 만들어 보자.

package com.baeldung.modules.hello;

public interface HelloInterface {
    void sayHello();
}

 

 이제 com.baeldung.modules.hello.impl라는 패키지를 새로 만든 후, 이 인터페이스를 구현하는 클래스를 아래와 같이 만들어보자. 

package com.baeldung.modules.hello.impl;

import com.baeldung.modules.hello.HelloInterface;

public class HelloImpl implements HelloInterface {

    @Override
    public void sayHello() {
        System.out.println("Hello!");
    }
}

 그 다음 아래와 같이 hello.modules 모듈 안의 module-info.java에 추가한다.

module hello.modules {
    exports com.baeldung.modules.hello;
    provides com.baeldung.modules.hello.HelloInterface with com.baeldung.modules.hello.impl.HelloImpl;
}

 위에서는 어떤 클래스가 인터페이스를 구현했는지 명시하고 있다.

 이제 이 서비스를 사용할 차례이다. main.app 모듈의 module-info.java에 다음과 같이 추가한다.

module main.app {
    requires hello.modules;
    uses com.baeldung.modules.hello.HelloInterface;
}

 마지막으로, MainApp 클래스를 아래와 같이 변경한다.

package com.baeldung.modules.main;

import com.baeldung.modules.hello.HelloInterface;
import com.baeldung.modules.hello.HelloModules;

import java.util.ServiceLoader;

public class MainApp {
    public static void main(String[] args) {
        HelloModules.doSomething();

        Iterable<HelloInterface> services = ServiceLoader.load(HelloInterface.class);
        HelloInterface service = services.iterator().next();
        service.sayHello();
    }
}

 다시 컴파일하고 실행하면 아래와 같은 결과를 확인할 수 있다.

$ sh compile-simple-modules.sh
$ sh run-simple-module-app.sh 
Hello, Modules!
Hello!

 우리는 'provides…with' 와 'uses' 키워드를 사용함으로써 우리의 코드가 어떻게 쓰이는지 좀 더 명시적으로 나타낼 수 있다. 또한 인터페이스의 구현은 노출시키지 않은채 인터페이스만 노출시킴으로써, 보다 캡슐화된 구조를 가지게 될 수 있다.

 

* https://www.baeldung.com/java-9-modularity을 기반으로 작성되었으나, 보다 수월한 이해를 위해 일부 소스 코드를 수정하였다. 따라서 소스코드를 위한 별도의 리파지토리를 여기에 제공하겠다. 

 

※ 참조

https://www.baeldung.com/java-9-modularity

반응형

+ Recent posts