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.java
fail.
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 /lib
direktori. Di dalam direktori itu terdapat src.zip
fail. Buka zip ke dalam /src
direktori.
Lihat ke dalam /src
direktori, dan arahkan ke /java.base
direktori. Di sana anda akan menemui module-info.java
failnya. Buka.
Selepas komen Javadoc di bahagian depan, anda akan menemui bahagian yang dinamakan module java.base
diikuti dengan rangkaian exports
baris. 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.base
modul. Ini adalah inti pati modul mengumpulkan pakej.
Bahagian lain exports
adalah requires
arahan. 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.java
fail. 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.java
fail: /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.java
definisi 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.mod2
modul dan memerlukan com.javaworld.mod1
.
Di dalam /com.javaworld.mod2
direktori, 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.Name
kelas. 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.