Language/JAVA

[JAVA] 모듈

IT수정 2024. 9. 5. 14:05

Java 9부터 지원하는 모듈(Module)은 패키지 관리 기능까지 포함된 라이브러리이다. 일반 라이브러리는 내부에 포함된 모든 패키지에 외부 프로그램에서의 접근이 가능하지만, 모듈은 다음과 같이 일부패키지를 은닉하여 접근할 수 없게끔 할 수 있다.

 

또 다른 차이점은 모듈은 자신이 실행할 때 필요로 하는 의존 모듈을 모듈 기술자(module-info.java)에 기술할 수 있기 때문에 모듈 간의 의존 관계를 쉽게 파악할 수 있다는 것이다.

 

모듈도 라이브러리 이므로 JAR 파일 형태로 배포할 수 있다. 응용프로그램을 개발할 때 원하는 기능의 모듈(JAR) 파일을 다운로드해서 이용하면 된다.

 

대규모 응용프로그램은 기능별로 모듈화(Modulization) 해서 개발할 수도 있다. 모듈별로 개발하고 조립하는 방식을 사용하면 재사용성 및 유지보수에 유리하기 때문이다.

 

응용프로그램 모듈화

응용프로그램은 하나의 프로젝트로도 개발이 가능하지만, 이것을 기능별로 서브 프로젝트(모듈)로 쪼갠 다음 조합해서 개발할 수도 있다.

 

응용프로그램의 규모가 커질수록 협업과 유지보수 측면에서 서브 모듈로 쪼개서 개발하는 것이 유리하며, 이렇게 개발된 모듈들은 다른 응용프로그램에서도 재사용이 가능하다. 다음은 이클립스의 모듈 생성 및 사용법이다.

 

my_module_a 모듈 생성

1. 이클립스 메뉴에서 [File] - [New] - [Java Project]를 선택한다. [Create a Java Project] 대화상자가 나타나면 다음과 같이 입력하고 [Finish] 버튼을 클릭한다.

Project name: my_module_a
Module:
[체크] Create module-info.java file (중요)
Module name: my_module_a

 

2. my_module_a 모듈의 src 폴더에 pack1과 pack2 패키지를 생성한다. 그리고 각 패키지에 A 클래스와 B 클래스를 생성한 후, 각각 하나의 메서드를 선언한다.

package pack1;

public class A {
	public void method() {
	System.out.println("A-method 실행")
    }
  }
package pack2;

public class B {
	public void method() {
	System.out.println("B-method 실행")
    }
  }

 

3. my_module_a 모듈이 포함하고 있는 두개의 pack1과 pack2를 외부에서 사용할 수 있도록 모듈 기술자(module-info.java)를 다음과 같이 작성한다. exports 키워드는 모듈이 가지고 있는 패키지를 외부에서 사용할 수 있도록 노출시키는 역할을 한다.

module my_module_a {
	exports pack1;
    exports pack2;
    }

 

my_module_b 모듈 생성

1. my_module_a의 방법과 똑같이 수행한다. 단, 패키지 이름은 pack3, pack4로 하고 class 이름도 C, D로 한다.

 

my_application_2 프로젝트 생성

이제 my_module_a와 my_module_b를 조합하는 my_application_2 프로젝트를 생성해 보자.

 

1. 이클립스 메뉴에서 [File] - [New] - [Java Project]를 선택한다. [Create a Java Project] 대화상자가 나타나면 다음과 같이 입력하고 [Finish] 버튼을 클릭한다.

Project name: my_application_2
Module:
[체크] Create module-info.java file (중요)
Module name: my_application_2

 

my_application_2는 모듈로 개발하는 것이 아니라 다른 모듈을 조합하는 응용프로그램을 위한 프로젝트이다. 그럼에도 불구하고 모듈 기술자가 필요하다. 그 이유는 어떤 모듈을 가져와 사용할 것인지 기술해야 하기 때문이다.

 

2. my_application_2 모듈은 my_module_a와 my_module_b 모듈에서 제공하는 패키지를 사용해야 하므로 두 모듈에 대한 의존 설정이 필요하다. my_application_2의 모듈 기술자(module-info.java)를 열고 다음과 같이 작성한다.

module my_application_2 {
	requires my_module_a;
    requires my_module_b;
    }

 

requires 키워드는 my_application_2 모듈을 컴파일하거나 실행할 때 필요한 의존 모듈을 지정한다. 실행하면 컴파일 에러가 발생하는데, 아직 my_application_2 모듈은 my_module_a와 my_module_b 모듈이 있는 경로를 모르기 때문이다.

 

3. Package Explorer 뷰에서 [my_application_2]을 선택하고 마우스 오른쪽 버튼으로 클릭하여 [Build Path] - [Configure Build Path] 버튼을 클릭 후 [Projects] 탭을 선택한다. 그리고 Required projects on the build path에서 Modulepath 항목을 선택하고 [Add] 버튼을 클릭한다.

 

4. [Required Projects Selection] 대화상자가 나타나면 my_module_a와 my_module_b 모듈의 체크박스에 체크하고 [OK] 버튼을 클릭한다.

 

5. [Project] 탭에 두 모듈이 추가된 것을 확인하고 [Apply and Close] 버튼을 클릭한다.

 

6. my_application_2 모듈의 src 폴더에서 app 패키지를 생성한다. 그리고 Main 클래스를 생성하고 다음과 같이 작성한 후 실행해 보자.

package app;

import pack1.A;
import pack2.B;
import pack3.C;
import pack4.D;

public class Main {
	public static void Main(String[] args) {
    	A a = new A();
        a.method();
        
        B b = new B();
        b.method();
        
        C c = new C();
        c.method();
        
        D d = new D();
        d.method();
        }
    }

 

실행 결과

A-method 실행
B-method 실행
C-method 실행
D-method 실행

 

모듈 배포용 JAR 파일 생성

모듈 개발을 완료했다면 다른 모듈에서 쉽게 사용할 수 있도록 바이트코드 파일(.class)로 구성된 배포용 JAR 파일을 생성해 보자.

 

1. my_module_a와 my_module_b 모듈에 각각 JAR파일을 저장할 dist 폴더를 생성한다.

 

2. my_module_a 모듈을 선택하고 마우스 오른쪽 버튼으로 클릭하여 [Export]를 선택한다.

 

3. Java 항목을 확장하고 JAR file을 선택한 후, [Next] 버튼을 클릭한다.

 

4. my_module_a를 확장하여 src 폴더에만 체크박스에 체크하고 나머지는 체크 해제 한다.

 

5. Select the export diestination에서 [Browse] 버튼을 클릭하고, my_module_a 모듈의 dist 폴더로 이동한다. 파일 이름은 ' my_module_a.jar'로 입력하고 저장한다.

 

6. Package Explorer 뷰에서 my_module_a 모듈을 선택하고 [Refresh]를 선택한다. dist 폴더에 JAR파일이 생성되었는지 확인한다. my_module_b도 동일한 방법으로 생성한다.

 

my_application_3 프로젝트 생성

새로운 프로젝트를 생성해서 두 개의 모듈 JAR 파일을 가져와 사용해 보자.

 

1. 이클립스 메뉴에서 [File] - [New] - [Java Project]를 선택한다. [Create a Java Project] 대화상자가 나타나면 다음과 같이 입력하고 [Finish] 버튼을 클릭한다.

Project name: my_application_3
Module:
[체크] Create module-info.java file (중요)
Module name: my_application_3

 

2. Package Explorer 뷰에서 my_application_3을 선택하고 마우스 오른쪽 버튼으로 클릭하여 [Build Path] - [Configure Build Path] 메뉴를 선택한다. [Libraries] 탭의 JAR and class folders on the build path에서 Modulepath 항목을 선택한 후, [Add External JARs] 버튼을 클릭한다.

 

3. my_module_a와 my_module_b 모듈의 dist 폴더로 각각 이동해서 my_module_a.jar 파일과 my_module_b.jar 파일을 추가한다. 그리고 [Apply and Close] 버튼을 클릭한다.

 

4. my_application_3 프로젝트는 my_application_a 모듈과 my_application_b 모듈을 사용해야 하므로 두 모듈 프로젝트에 대한 의존 설정이 필요하다. 모듈 기술자를 열고 다음과 같이 작성한다.

module my_application_3 {
	requires my_module_a;
    requires my_module_b;
    }

 

5. my_application_3 모듈의 src 폴더에서 app 패키지를 생성한다. 그리고 Main 클래스를 생성한 후 다음과 같이 작성하고 실행한다.

package app;

import pack1.A;
import pack2.B;
import pack3.C;

public class Main {
	public static void main(String[] args) {
    	A a = new A();
        a.method();
        
        B b = new B();
        b.method();
        
        C c = new C();
        c.method();
        }
    }

 

집합 모듈

집합 모듈은 여러 모듈을 모아놓은 것을 말한다. 자주 사용되는 모듈들을 일일이 requires 하는 번거로움을 피하고 싶을 때 집합 모듈을 생성하면 편리하다. 집합 모듈은 자체적인 패키지를 가지지 않고, 모듈 기술자에 전이 의존 설정만 한다. 예를 들어 my_module은 my_module_a와 my_module_b을 제공하는 집합 모듈이라고 가정해보자. my_module의 모듈 기술자는 다음과 같이 작성할 수 있다.

module my_module {
	requires transitive my_module_a;
    requires transitive my_module_b;
    }

 

이때 다른 모듈에서 my_module만 requires 하게 되면 my_module_a와 my_module_b 모두 사용할 수 있게 된다.

 

패키지 은닉

모듈은 모듈 기술자에서 exports 키워드를 사용해 내부 패키지 중 외부에서 사용할 패키지를 지정한다. exports 되지 않은 패키지는 자동적으로 은닉된다.

 

리플렉션 허용

은닉된 패키지는 기본적으로 다른 모듈에 의해 리플렉션을 허용하지 않는다. 리플렉션(Reflection)이란 실행 도중에 타입(클래스, 인터페이스 등)을 검사하고 구성 멤버를 조사하는 것을 말한다.

 

경우에 따라서는 은닉된 패키지도 리플렉션을 허용해야 할 때가 있다. 모듈은 모듈 기술자를 통해 모듈 전체 또는 지정된 패키지에 대해 리플렉션을 허용할 수 있고, 특정 외부 모듈에서만 리플렉션을 허용할 수도 있다.

 

모듈 전체를 리플렉션 허용

open module 모듈명 {
	...
	}

 

지정된 패키지에 대해 리플렉션 허용

module 모듈명 {
	...
    open 패키지1;
    open 패키지2;
    }

 

지정된 패키지에 대해 특정 외부 모듈에서만 리플렉션 허용

module 모듈명 {
	opens 패키지1 to 외부모듈명, 외부모듈명, ...;
    opens 패키지2 to 외부모듈명;
    }

 

export 된 패키지는 언제든지 리플렉션이 가능하므로 opens로 지정할 필요가 없다. opens는 은닉된 패키지 중에서 특정 패키지에 대한 리플렉션을 허용한다.

 

자바 표준 모듈

자바 프로그램이라면 반드시 활용해야 하는 라이브러리가 있다. 바로 JDK가 제공하는 표준 라이브러리다. 표준 라이브러리를 모듈화 한 이유는 응용프로그램을 실행하는데 필요한 모듈만으로 구성된 작은 사이즈의 자바 실행 환경(JRE)을 만들기 위해서이다.

'Language > JAVA' 카테고리의 다른 글

[JAVA] Object 클래스  (0) 2024.10.15
[JAVA] java.base 모듈  (1) 2024.10.15
[JAVA] 라이브러리  (2) 2024.09.05
[JAVA] 예외 처리  (0) 2024.09.05
[JAVA] 중첩 클래스  (1) 2024.09.04