Apa itu JPMS? Memperkenalkan Sistem Modul Platform Java

Hingga Java 9, elemen organisasi kode tingkat atas Java telah menjadi paketnya. Dimulai dengan Java 9 yang berubah: di atas paket sekarang adalah modul. Modul ini mengumpulkan paket terkait bersama-sama.

Java Platform Module System (JPMS) adalah struktur tingkat kode, jadi tidak mengubah fakta bahwa kami mengemas Java ke dalam file JAR. Pada akhirnya, semuanya masih digabungkan dalam file JAR. Sistem modul menambahkan deskriptor tingkat tinggi baru yang dapat digunakan JAR, dengan memasukkan module-info.javafile.

Aplikasi dan organisasi skala besar akan memanfaatkan modul untuk mengatur kode dengan lebih baik. Tetapi semua orang akan menggunakan modul, karena JDK dan kelasnya sekarang termodulasi.

Mengapa Java membutuhkan modul

JPMS adalah hasil dari proyek Jigsaw, yang dilakukan dengan tujuan sebagai berikut: 

  • Permudah pengembang untuk mengatur aplikasi dan perpustakaan besar
  • Tingkatkan struktur dan keamanan platform dan JDK itu sendiri
  • Tingkatkan kinerja aplikasi
  • Tangani dekomposisi platform dengan lebih baik untuk perangkat yang lebih kecil

Perlu dicatat bahwa JPMS adalah fitur SE (Edisi Standar), dan oleh karena itu memengaruhi setiap aspek Java dari bawah ke atas. Karena itu, perubahan tersebut dirancang untuk memungkinkan sebagian besar kode berfungsi tanpa modifikasi saat berpindah dari Java 8 ke Java 9. Ada beberapa pengecualian untuk ini, dan kami akan mencatatnya nanti dalam ikhtisar ini.

Ide utama di balik modul adalah untuk memungkinkan pengumpulan paket terkait yang terlihat oleh modul, sambil menyembunyikan elemen dari konsumen eksternal modul. Dengan kata lain, modul memungkinkan tingkat enkapsulasi lain.

Jalur kelas vs. jalur modul

Di Java hingga saat ini jalur kelas telah menjadi garis bawah untuk apa yang tersedia untuk aplikasi yang sedang berjalan. Meskipun jalur kelas melayani tujuan ini dan dipahami dengan baik, ini akhirnya menjadi keranjang besar yang tidak berdiferensiasi tempat semua dependensi ditempatkan.

Jalur modul menambahkan level di atas jalur kelas. Ini berfungsi sebagai wadah untuk paket dan menentukan paket apa yang tersedia untuk aplikasi.

Modul di JDK

JDK sendiri sekarang terdiri dari modul. Mari kita mulai dengan melihat mur dan baut JPMS di sana.

Jika Anda memiliki JDK di sistem Anda, Anda juga memiliki sumbernya. Jika Anda tidak terbiasa dengan JDK dan cara mendapatkannya, lihat artikel ini.

Di dalam direktori instalasi JDK Anda adalah sebuah /libdirektori. Di dalam direktori itu ada src.zipfile. Buka zip itu ke /srcdirektori.

Lihat ke dalam /srcdirektori, dan arahkan ke /java.basedirektori. Di sana Anda akan menemukan module-info.javafile tersebut. Buka itu.

Setelah komentar Javadoc di kepala, Anda akan menemukan bagian bernama  module java.base diikuti oleh serangkaian exportsbaris. Kami tidak akan memikirkan formatnya di sini, karena ini menjadi cukup esoterik. Detailnya dapat ditemukan di sini.

Anda dapat melihat bahwa banyak paket yang sudah dikenal dari Java, seperti java.io, diekspor dari java.basemodul. Ini adalah inti dari modul yang mengumpulkan paket-paket.

Sisi lain dari  exportsadalah requiresinstruksi. Ini memungkinkan modul untuk dibutuhkan oleh modul yang sedang didefinisikan.

Saat menjalankan compiler Java terhadap modul, Anda menentukan jalur modul dengan cara yang mirip dengan jalur kelas. Hal ini memungkinkan ketergantungan untuk diselesaikan.

Membuat proyek Java modular

Mari kita lihat bagaimana proyek Java termodulasi disusun.

Kita akan membuat program kecil yang memiliki dua modul, satu yang menyediakan ketergantungan dan yang lainnya menggunakan ketergantungan itu dan mengekspor kelas utama yang dapat dieksekusi.

Buat direktori baru di suatu tempat yang nyaman di sistem file Anda. Sebut saja /com.javaworld.mod1. Sesuai ketentuan, modul Java berada di direktori yang memiliki nama yang sama dengan modul.

Sekarang, di dalam direktori ini, buat module-info.javafile. Di dalam, tambahkan konten dari Daftar 1.

Daftar 1: com.javaworld.mod1 / module-info.java

module com.javaworld.mod1 { exports com.javaworld.package1; }

Perhatikan bahwa modul dan paket yang diekspornya adalah nama yang berbeda. Kami mendefinisikan modul yang mengekspor paket.

Sekarang membuat file di jalan ini, di dalam direktori yang berisi module-info.javaberkas: /com.javaworld.mod1/com/javaworld/package1. Beri nama file  Name.java. Taruh isi Listing 2 di dalamnya.

Kode 2: Name.java

 package com.javaworld.package1; public class Name { public String getIt() { return "Java World"; } } 

Kode 2 akan menjadi kelas, paket, dan modul tempat kita bergantung.

Sekarang mari buat direktori lain yang sejajar /com.javaworld.mod1 dan beri nama /com.javaworld.mod2. Di direktori ini, mari buat module-info.javadefinisi modul yang mengimpor modul yang sudah kita buat, seperti pada Listing 3.

Daftar 3: com.javaworld.mod2 / module-info.java

 module com.javaworld.mod2 { requires com.javaworld.mod1; } 

Kode 3 cukup jelas. Ini mendefinisikan com.javaworld.mod2modul dan membutuhkan com.javaworld.mod1.

Di dalam /com.javaworld.mod2direktori, membuat jalur kelas seperti: /com.javaworld.mod2/com/javaworld/package2.

Sekarang tambahkan file di dalam yang disebut Hello.java, dengan kode yang disediakan di Listing 4.

Kode 4: Hello.java

 package com.javaworld.package2; import com.javaworld.package1.Name; public class Hello { public static void main(String[] args) { Name name = new Name(); System.out.println("Hello " + name.getIt()); } } 

Dalam Kode 4, kita mulai dengan mendefinisikan paket, kemudian mengimpor com.javawolrd.package1.Namekelas. Perhatikan bahwa elemen-elemen ini berfungsi seperti biasanya. Modul telah mengubah cara paket tersedia pada tingkat struktur file, bukan pada tingkat kode.

Similarly, the code itself should be familiar to you. It simply creates a class and calls a method on it to create a classic “hello world” example.

Running the modular Java example

The first step is to create directories to receive the output of the compiler. Create a directory called /target at the root of the project. Inside, create a directory for each module: /target/com.javaworld.mod1 and /target/com.javaworld.mod2.

Step 2 is to compile the dependency module, outputting it to the /target directory. At the root of the project, enter the command in Listing 5. (This assumes the JDK is installed.)

Listing 5: Building Module 1

 javac -d target/com.javaworld.mod1 com.javaworld.mod1/module-info.java com.javaworld.mod1/com/javaworld/package1/Name.java 

This will cause the source to be built along with its module information.

Step 3 is to generate the dependent module. Enter the command shown in Listing 6.

Listing 6: Building Module 2

 javac --module-path target -d target/com.javaworld.mod2 com.javaworld.mod2/module-info.java com.javaworld.mod2/com/javaworld/package2/Hello.java 

Let’s take a look at Listing 6 in detail. It introduces the module-path argument to javac. This allows us to define the module path in similar fashion to the --class-path switch. In this example, we are passing in the target directory, because that is where Listing 5 outputs Module 1.

Next, Listing 6 defines (via the -d switch) the output directory for Module 2. Finally, the actual subjects of compilation are given, as the module-info.java file and class contained in Module 2.

To run, use the command shown in Listing 7.

Listing 7: Executing the module main class

 java --module-path target -m com.javaworld.mod2/com.javaworld.package2.Hello 

The --module-path switch tells Java to use /target directory as the module root, i.e., where to search for the modules. The -m switch is where we tell Java what our main class is. Notice that we preface the fully qualified class name with its module.

You will be greeted with the output Hello Java World.

Backward compatibility 

You may well be wondering how you can run Java programs written in pre-module versions in the post Java 9 world, given that the previous codebase knows nothing of the module path. The answer is that Java 9 is designed to be backwards compatible. However, the new module system is such a big change that you may run into issues, especially in large codebases.

When running a pre-9 codebase against Java 9, you may run into two kinds of errors: those that stem from your codebase, and those that stem from your dependencies.

For errors that stem from your codebase, the following command can be helpful: jdeps. This command when pointed at a class or directory will scan for what dependencies are there, and what modules those dependencies rely on.

For errors that stem from your dependencies, you can hope that the package you are depending on will have an updated Java 9 compatible build. If not you may have to search for alternatives.

One common error is this one:

How to resolve java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException

This is Java complaining that a class is not found, because it has migrated to a module without visibility to the consuming code. There are a couple of solutions of varying complexity and permanency, described here.

Sekali lagi, jika Anda menemukan kesalahan seperti itu dengan ketergantungan, periksa proyeknya. Mereka mungkin memiliki build Java 9 untuk Anda gunakan.

JPMS adalah perubahan yang cukup luas dan akan membutuhkan waktu untuk mengadopsinya. Untungnya, tidak ada terburu-buru yang mendesak, karena Java 8 adalah rilis dukungan jangka panjang.

Meskipun demikian, dalam jangka panjang, proyek lama perlu bermigrasi, dan yang baru perlu menggunakan modul dengan cerdas, semoga memanfaatkan beberapa manfaat yang dijanjikan.

Artikel ini, "Apa itu JPMS? Memperkenalkan Sistem Modul Platform Java" pertama kali diterbitkan oleh JavaWorld.