Pengantar Project Jigsaw

1. Perkenalan

Project Jigsaw adalah proyek payung dengan fitur-fitur baru yang ditujukan pada dua aspek:

  • pengenalan sistem modul dalam bahasa Java
  • dan implementasinya dalam sumber JDK dan runtime Java

Pada artikel ini, kami akan memperkenalkan Anda ke proyek Jigsaw dan fitur-fiturnya dan akhirnya menyelesaikannya dengan aplikasi modular sederhana.

2. Modularitas

Sederhananya, modularitas adalah prinsip desain yang membantu kita mencapai:

  • kopling longgar antar komponen
  • kontrak yang jelas dan ketergantungan antar komponen
  • implementasi tersembunyi menggunakan enkapsulasi yang kuat

2.1. Satuan Modularitas

Sekarang muncul pertanyaan seperti apa unit modularitas? Di dunia Java, terutama dengan OSGi, JAR dianggap sebagai unit modularitas.

JAR memang membantu dalam mengelompokkan komponen terkait, tetapi mereka memiliki beberapa keterbatasan:

  • kontrak eksplisit dan ketergantungan antara JAR
  • enkapsulasi elemen yang lemah dalam JAR

2.2. JAR Neraka

Ada masalah lain dengan JAR - neraka JAR. Beberapa versi JAR yang ada di classpath, mengakibatkan ClassLoader memuat kelas pertama yang ditemukan dari JAR, dengan hasil yang sangat tidak terduga.

Masalah lain dengan JVM yang menggunakan classpath adalah bahwa kompilasi aplikasi akan berhasil, tetapi aplikasi akan gagal pada waktu proses dengan ClassNotFoundException , karena JAR yang hilang di classpath saat runtime.

2.3. Unit Modularitas Baru

Dengan semua keterbatasan ini, saat menggunakan JAR sebagai unit modularitas, pembuat bahasa Java membuat konstruksi baru dalam bahasa yang disebut modul. Dan dengan ini, ada sistem modular baru yang direncanakan untuk Java.

3. Proyek Jigsaw

Motivasi utama untuk proyek ini adalah:

  • membuat sistem modul untuk bahasa - diimplementasikan menurut JEP 261
  • menerapkannya ke sumber JDK - diimplementasikan menurut JEP 201
  • memodularkan pustaka JDK - diimplementasikan di bawah JEP 200
  • perbarui runtime untuk mendukung modularitas - diimplementasikan di bawah JEP 220
  • dapat membuat runtime yang lebih kecil dengan subset modul dari JDK - diimplementasikan di bawah JEP 282

Inisiatif penting lainnya adalah merangkum API internal di JDK, mereka yang berada di bawah paket matahari. * Dan API non-standar lainnya. API ini tidak pernah dimaksudkan untuk digunakan oleh publik dan tidak pernah direncanakan untuk dipertahankan. Tetapi kekuatan API ini membuat pengembang Java memanfaatkannya dalam pengembangan pustaka, kerangka kerja, dan alat yang berbeda. Ada penggantian yang disediakan untuk beberapa API internal dan yang lainnya telah dipindahkan ke modul internal.

4. Alat Baru untuk Modularitas

  • jdeps - membantu dalam menganalisis basis kode untuk mengidentifikasi dependensi pada JDK API dan JAR pihak ketiga. Ia juga menyebutkan nama modul tempat JDK API dapat ditemukan. Ini membuatnya lebih mudah dalam memodularisasi basis kode
  • jdeprscan - membantu dalam menganalisis basis kode untuk penggunaan API apa pun yang tidak digunakan lagi
  • jlink - membantu dalam membuat runtime yang lebih kecil dengan menggabungkan aplikasi dan modul JDK
  • jmod - membantu bekerja dengan file jmod. jmod adalah format baru untuk memaketkan modul. Format ini memungkinkan menyertakan kode asli, file konfigurasi, dan data lain yang tidak sesuai dengan file JAR

5. Arsitektur Sistem Modul

Sistem modul, diimplementasikan dalam bahasa, mendukung ini sebagai konstruksi tingkat atas, seperti paket. Pengembang dapat mengatur kode mereka ke dalam modul dan mendeklarasikan ketergantungan di antara mereka dalam file definisi modul masing-masing.

File definisi modul, bernama module-info.java , berisi:

  • namanya
  • paket yang disediakan untuk umum
  • modul tempat bergantungnya
  • layanan apa pun yang dikonsumsi
  • implementasi apa pun untuk layanan yang disediakannya

Dua item terakhir dalam daftar di atas tidak umum digunakan. Mereka hanya digunakan ketika layanan disediakan dan digunakan melalui antarmuka java.util.ServiceLoader .

Struktur umum modul terlihat seperti:

src |----com.baeldung.reader | |----module-info.java | |----com | |----baeldung | |----reader | |----Test.java |----com.baeldung.writer |----module-info.java |----com |----baeldung |----writer |----AnotherTest.java

Ilustrasi di atas mendefinisikan dua modul: com.baeldung.reader dan com.baeldung.writer . Masing-masing memiliki definisinya yang ditentukan dalam module-info.java dan file kode masing-masing ditempatkan di bawah com / baeldung / reader dan com / baeldung / writer .

5.1. Istilah Definisi Modul

Mari kita lihat beberapa terminologi; kita akan gunakan saat mendefinisikan modul (yaitu, di dalam module-info.java) :

  • module : file definisi modul dimulai dengan kata kunci ini diikuti dengan nama dan definisinya
  • Requirement : digunakan untuk menunjukkan modul tempat bergantung; nama modul harus ditentukan setelah kata kunci ini
  • transitif : ditentukan setelahkata kunci membutuhkan ; ini berarti bahwa setiap modul yang bergantung pada definisi modul memerlukan transitif mendapatkan ketergantungan implisit pada < modulename>
  • ekspor : digunakan untuk menunjukkan paket-paket dalam modul yang tersedia untuk umum; nama paket harus ditentukan setelah kata kunci ini
  • opens: is used to indicate the packages that are accessible only at runtime and also available for introspection via Reflection APIs; this is quite significant to libraries like Spring and Hibernate, highly rely on Reflection APIs; opens can also be used at the module level in which case the entire module is accessible at runtime
  • uses: is used to indicate the service interface that this module is using; a type name, i.e., complete class/interface name, has to specified after this keyword
  • provides … with ...: they are used to indicate that it provides implementations, identified after the with keyword, for the service interface identified after the provides keyword

6. Simple Modular Application

Let us create a simple modular application with modules and their dependencies as indicated in the diagram below:

The com.baeldung.student.model is the root module. It defines model class com.baeldung.student.model.Student, which contains the following properties:

public class Student { private String registrationId; //other relevant fields, getters and setters }

It provides other modules with types defined in the com.baeldung.student.model package. This is achieved by defining it in the file module-info.java:

module com.baeldung.student.model { exports com.baeldung.student.model; }

The com.baeldung.student.service module provides an interface com.baeldung.student.service.StudentService with abstract CRUD operations:

public interface StudentService { public String create(Student student); public Student read(String registrationId); public Student update(Student student); public String delete(String registrationId); }

It depends on the com.baeldung.student.model module and makes the types defined in the package com.baeldung.student.service available for other modules:

module com.baeldung.student.service { requires transitive com.baeldung.student.model; exports com.baeldung.student.service; }

We provide another module com.baeldung.student.service.dbimpl, which provides the implementation com.baeldung.student.service.dbimpl.StudentDbService for the above module:

public class StudentDbService implements StudentService { public String create(Student student) { // Creating student in DB return student.getRegistrationId(); } public Student read(String registrationId) { // Reading student from DB return new Student(); } public Student update(Student student) { // Updating student in DB return student; } public String delete(String registrationId) { // Deleting student in DB return registrationId; } }

It depends directly on com.baeldung.student.service and transitively on com.baeldung.student.model and its definition will be:

module com.baeldung.student.service.dbimpl { requires transitive com.baeldung.student.service; requires java.logging; exports com.baeldung.student.service.dbimpl; }

The final module is a client module – which leverages the service implementation module com.baeldung.student.service.dbimpl to perform its operations:

public class StudentClient { public static void main(String[] args) { StudentService service = new StudentDbService(); service.create(new Student()); service.read("17SS0001"); service.update(new Student()); service.delete("17SS0001"); } }

And its definition is:

module com.baeldung.student.client { requires com.baeldung.student.service.dbimpl; }

7. Compiling and Running the Sample

We have provided scripts for compiling and running the above modules for the Windows and the Unix platforms. These can be found under the core-java-9 project here. The order of execution for Windows platform is:

  1. compile-student-model
  2. compile-student-service
  3. compile-student-service-dbimpl
  4. compile-student-client
  5. run-student-client

The order of execution for Linux platform is quite simple:

  1. compile-modules
  2. run-student-client

In the scripts above, you will be introduced to the following two command line arguments:

  • –module-source-path
  • –module-path

Java 9 is doing away with the concept of classpath and instead introduces module path. This path is the location where the modules can be discovered.

We can set this by using the command line argument: –module-path.

To compile multiple modules at once, we make use of the –module-source-path. This argument is used to provide the location for the module source code.

8. Module System Applied to JDK Source

Every JDK installation is supplied with a src.zip. This archive contains the code base for the JDK Java APIs. If you extract the archive, you will find multiple folders, few starting with java, few with javafx and the rest with jdk. Each folder represents a module.

The modules starting with java are the JDK modules, those starting with javafx are the JavaFX modules and others starting with jdk are the JDK tools modules.

All JDK modules and all the user defined modules implicitly depend on the java.base module. The java.base module contains commonly used JDK APIs like Utils, Collections, IO, Concurrency among others. The dependency graph of the JDK modules is:

You can also look at the definitions of the JDK modules to get an idea of the syntax for defining them in the module-info.java.

9. Conclusion

In this article, we looked at creating, compiling and running a simple modular application. We also saw how the JDK source code had been modularized.

There are few more exciting features, like creating smaller runtime using the linker tool – jlink and creating modular jars among other features. We will introduce you to those features in details in future articles.

Project Jigsaw adalah perubahan besar, dan kami harus menunggu dan melihat bagaimana hal itu diterima oleh ekosistem pengembang, khususnya dengan alat dan pembuat pustaka.

Kode yang digunakan dalam artikel ini dapat ditemukan di GitHub.