Apa itu JPMS? Memperkenalkan Sistem Modul Platform Java

Sehingga Java 9, elemen organisasi kod tingkat atas Java telah menjadi paket. Bermula dengan Java 9 yang berubah: di atas pakej sekarang adalah modul. Modul mengumpulkan pakej berkaitan bersama.

Sistem Modul Platform Java (JPMS) adalah struktur tingkat kod, jadi tidak mengubah fakta bahwa kami mengemas Java ke dalam file JAR. Pada akhirnya, semuanya masih digabungkan dalam fail JAR. Sistem modul menambah deskriptor tahap tinggi yang boleh digunakan oleh JAR, dengan memasukkan module-info.javafail.

Aplikasi dan organisasi berskala besar akan memanfaatkan modul untuk menyusun kod dengan lebih baik. Tetapi semua orang akan menggunakan modul, kerana JDK dan kelasnya kini dimodulasi.

Mengapa Java memerlukan modul

JPMS adalah hasil projek Jigsaw, yang dilaksanakan dengan tujuan yang dinyatakan berikut: 

  • Memudahkan pembangun menyusun aplikasi dan perpustakaan besar
  • Tingkatkan struktur dan keselamatan platform dan JDK itu sendiri
  • Tingkatkan prestasi aplikasi
  • Penguraian platform yang lebih baik untuk peranti yang lebih kecil

Perlu diperhatikan bahawa JPMS adalah ciri SE (Edisi Standard), dan oleh itu mempengaruhi setiap aspek Java dari bawah ke atas. Setelah itu, perubahan dirancang untuk membolehkan kebanyakan kod berfungsi tanpa modifikasi ketika berpindah dari Java 8 ke Java 9. Terdapat beberapa pengecualian untuk ini, dan kami akan mencatatnya kemudian dalam gambaran keseluruhan ini.

Idea utama di sebalik modul adalah membenarkan pengumpulan pakej berkaitan yang dapat dilihat oleh modul, sambil menyembunyikan elemen dari pengguna luaran modul. Dengan kata lain, modul memungkinkan tahap enkapsulasi yang lain.

Laluan kelas vs laluan modul

Di Jawa hingga sekarang jalur kelas telah menjadi garis bawah untuk apa yang tersedia untuk aplikasi yang sedang berjalan. Walaupun jalan kelas memenuhi tujuan ini dan difahami dengan baik, ia akhirnya menjadi baldi yang besar dan tidak dapat dibezakan di mana semua pergantungan diletakkan.

Laluan modul menambah tahap di atas laluan kelas. Ia berfungsi sebagai wadah untuk pakej dan menentukan pakej apa yang tersedia untuk aplikasi.

Modul dalam JDK

JDK itu sendiri terdiri daripada modul sekarang. Mari mulakan dengan melihat mur dan selak JPMS di sana.

Sekiranya anda mempunyai JDK pada sistem anda, anda juga mempunyai sumbernya. Sekiranya anda tidak mahir dengan JDK dan cara mendapatkannya, lihat artikel ini.

Di dalam direktori pemasangan JDK anda terdapat /libdirektori. Di dalam direktori itu terdapat src.zipfail. Buka zip ke dalam /srcdirektori.

Lihat ke dalam /srcdirektori, dan arahkan ke /java.basedirektori. Di sana anda akan menemui module-info.javafailnya. Buka.

Selepas komen Javadoc di bahagian depan, anda akan menemui bahagian yang dinamakan  module java.base diikuti dengan rangkaian exportsbaris. Kami tidak akan memikirkan formatnya di sini, kerana ia menjadi sangat esoterik. Maklumatnya boleh didapati di sini.

Anda dapat melihat bahawa banyak pakej biasa dari Java, seperti java.io, dieksport dari java.basemodul. Ini adalah inti pati modul mengumpulkan pakej.

Bahagian lain  exportsadalah requiresarahan. Ini membolehkan modul diperlukan oleh modul yang ditentukan.

Semasa menjalankan penyusun Java terhadap modul, anda menentukan jalur modul dengan cara yang serupa dengan jalur kelas. Ini membolehkan kemurungan diselesaikan.

Membuat projek Java modular

Mari kita lihat bagaimana struktur Java yang dimodulasi disusun.

Kami akan membuat program kecil yang mempunyai dua modul, satu yang menyediakan pergantungan dan satu lagi yang menggunakan kebergantungan itu dan mengeksport kelas utama yang dapat dilaksanakan.

Buat direktori baru di tempat yang sesuai pada sistem fail anda. Panggilnya /com.javaworld.mod1. Secara konvensional, modul Java hidup dalam direktori yang mempunyai nama yang sama dengan modul tersebut.

Sekarang, di dalam direktori ini, buat module-info.javafail. Di dalamnya, tambahkan kandungan dari Penyenaraian 1.

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

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

Perhatikan bahawa modul dan pakej yang dieksportnya adalah nama yang berbeza. Kami menentukan modul yang mengeksport pakej.

Sekarang membuat fail di atas jalan ini, di dalam direktori yang mengandungi module-info.javafail: /com.javaworld.mod1/com/javaworld/package1. Namakan fail  Name.java. Masukkan isi Penyenaraian 2 di dalamnya.

Penyenaraian 2: Name.java

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

Penyenaraian 2 akan menjadi kelas, pakej, dan modul di mana kita bergantung.

Sekarang mari kita buat direktori lain yang selari dengan /com.javaworld.mod1 dan memanggilnya /com.javaworld.mod2. Dalam direktori ini, mari buat module-info.javadefinisi modul yang mengimport modul yang telah kita buat, seperti dalam Penyenaraian 3.

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

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

Penyenaraian 3 cukup jelas. Ia menentukan com.javaworld.mod2modul dan memerlukan com.javaworld.mod1.

Di dalam /com.javaworld.mod2direktori, mencipta laluan kelas seperti demikian: /com.javaworld.mod2/com/javaworld/package2.

Sekarang tambahkan fail di dalam yang dipanggil Hello.java, dengan kod yang disediakan dalam Penyenaraian 4.

Penyenaraian 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 Penyenaraian 4, kita mulakan dengan menentukan pakej, kemudian mengimport com.javawolrd.package1.Namekelas. Perhatikan bahawa unsur-unsur ini berfungsi seperti biasa. Modul telah mengubah bagaimana pakej disediakan pada tahap struktur fail, bukan tahap kod.

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 menemui kesilapan seperti ini, periksa projek tersebut. Mereka mungkin memiliki build Java 9 untuk Anda gunakan.

JPMS adalah perubahan yang cukup besar dan memerlukan masa untuk diterima pakai. Nasib baik, tidak ada yang mendesak, kerana Java 8 adalah pelepasan sokongan jangka panjang.

Yang dikatakan, dalam jangka masa panjang, projek yang lebih lama perlu dimigrasikan, dan yang baru perlu menggunakan modul dengan bijak, semoga memanfaatkan beberapa faedah yang dijanjikan.

Kisah ini, "Apa itu JPMS? Memperkenalkan Sistem Modul Platform Java" pada awalnya diterbitkan oleh JavaWorld.