Tại sao dự án Jigsaw / JPMS?


79

Đối với tôi, hệ thống quản lý gói của Java luôn có vẻ đơn giản và hiệu quả. Nó được sử dụng nhiều bởi chính JDK. Chúng tôi đang sử dụng nó để bắt chước khái niệm không gian tên và mô-đun.

Là gì dự án Jigsaw (aka Java Hệ thống Platform Module ) cố gắng để điền vào?

Từ trang web chính thức:

Mục tiêu của Dự án này là thiết kế và triển khai hệ thống mô-đun tiêu chuẩn cho Nền tảng Java SE, và áp dụng hệ thống đó cho chính Nền tảng và cho JDK.

Câu trả lời:


100

Jigsaw và OSGi đang cố gắng giải quyết cùng một vấn đề: làm thế nào để cho phép các mô-đun thô hơn tương tác trong khi che chắn bên trong của chúng.

Trong trường hợp của Jigsaw, các mô-đun chi tiết hơn bao gồm các lớp Java, các gói và các phụ thuộc của chúng.

Đây là một ví dụ: Spring và Hibernate. Cả hai đều phụ thuộc vào JAR CGLIB của bên thứ ba, nhưng chúng sử dụng các phiên bản khác nhau, không tương thích của JAR đó. Bạn có thể làm gì nếu dựa vào tiêu chuẩn JDK? Bao gồm cả phiên bản mà Spring muốn ngắt chế độ Hibernate và ngược lại.

Tuy nhiên, nếu bạn có một mô hình cấp cao hơn như Jigsaw, bạn có thể dễ dàng quản lý các phiên bản khác nhau của JAR trong các mô-đun khác nhau. Hãy coi chúng như các gói cấp cao hơn.

Nếu bạn xây dựng Spring từ nguồn GitHub, bạn cũng sẽ thấy nó. Họ đã làm lại khuôn khổ để nó bao gồm một số mô-đun: cốt lõi, tính bền bỉ, v.v. Bạn có thể chọn và chọn tập hợp tối thiểu các phụ thuộc mô-đun mà ứng dụng của bạn cần và bỏ qua phần còn lại. Nó từng là một Spring JAR duy nhất, với tất cả các tệp .class trong đó.

Cập nhật: Năm năm sau - Jigsaw vẫn có thể có một số vấn đề cần giải quyết.


5
Điều gì sẽ xảy ra nếu bạn vẫn cần sử dụng cùng một mô-đun, nhưng hai phiên bản khác nhau của nó? Không phải họ chỉ thêm một số loại hỗ trợ để hai phiên bản của cùng một lớp có thể cùng tồn tại?
Didier A.

7
bài đăng này gây hiểu lầm vì những gì thực sự dự kiến ​​sẽ được phát hành trong java 9. Nó có thể là chính xác tại thời điểm viết bài.
xenoterracide

1
mreinhold.org/blog/jigsaw-complete Dự án hoàn thành và được phát hành cho Java 9
Zasz

@xenoterracide, bạn không thể trách ai đó không thông minh được. Bài đăng trước Java 9 năm năm. Bạn có đang xem lại mọi câu trả lời từ Jon Skeet không?
duffymo

Bài đăng này không có tuổi. Các mô-đun Java cố ý không giải quyết vấn đề lập phiên bản, hãy xem chủ đề này . Vẫn không có cách nào dễ dàng để có được những người bạn cũ của chúng ta NoSuchMethodErrorNoClassDefFoundError.
Tamas Hegedus

45

AFAIK Kế hoạch là làm cho JRE trở nên mô-đun hơn. Tức là có các lọ nhỏ hơn tùy chọn và / hoặc bạn chỉ có thể tải xuống / nâng cấp chức năng bạn cần.

Nó làm cho nó bớt cồng kềnh hơn và cung cấp cho bạn tùy chọn loại bỏ các mô-đun cũ mà có lẽ hầu hết mọi người không sử dụng.


7
Câu trả lời được chấp nhận là hợp lệ, nhưng câu trả lời này tốt hơn vì nó giải thích các hiệu ứng mong muốn thực tế. +1, rất xứng đáng.
Silviu Burcea

Tôi tò mò vì vậy điều này cũng có nghĩa là nếu tôi có Google Guava làm phụ thuộc, nhưng tôi chỉ sử dụng ImmutableList trong đó, thì tôi chỉ có thể nhập các phụ thuộc ImmutableList và bỏ phần còn lại của các lớp Guava?
tmn

1
@ThomasN. khi bạn sử dụng importtất cả điều này là giới thiệu lớp này vào không gian tên của lớp cho trình biên dịch. Nếu bạn không thực sự sử dụng nó, nó sẽ không xuất hiện trong mã byte được tạo. Nếu bạn thực sự sử dụng lớp, bạn cần phải có lớp đó và mọi lớp mà nó sử dụng trong thời gian chạy. Về lý thuyết, bạn có thể tạo một phiên bản rút gọn của API ổi chỉ có những gì bạn cần và sử dụng JAR đó thay thế. Trong thực tế, điều này dễ xảy ra lỗi và không hữu ích lắm trong hầu hết các trường hợp, và cuối cùng bạn chỉ thêm toàn bộ JAR như đã phát hành.
Peter Lawrey

43

Dựa trên bài phát biểu quan trọng của Mark Reinhold tại Devoxx Bỉ , Project Jigsaw sẽ giải quyết hai điểm đau chính:

  1. Classpath
  2. JDK nguyên khối khổng lồ

Có gì sai với Classpath?

Tất cả chúng ta đều biết về Địa ngục JAR . Thuật ngữ này mô tả tất cả các cách khác nhau mà quá trình tải lớp có thể không hoạt động. Các hạn chế được biết đến nhiều nhất của classpath là:

  • Thật khó để biết nếu có xung đột. xây dựng các công cụ như maven có thể thực hiện khá tốt công việc dựa trên tên hiện vật nhưng nếu bản thân các hiện vật có tên khác nhưng nội dung giống nhau, có thể xảy ra xung đột.
  • Vấn đề cơ bản với các tệp jar là chúng không phải là các thành phần. Chúng chỉ là một loạt các vùng chứa tệp sẽ được tìm kiếm tuyến tính. Classpath là một cách để tra cứu các lớp bất kể chúng nằm trong thành phần nào, gói nào hoặc mục đích sử dụng của chúng.

JDK nguyên khối khổng lồ

Bản chất nguyên khối lớn của JDK gây ra một số vấn đề:

  • Nó không phù hợp trên các thiết bị nhỏ. Mặc dù các thiết bị loại IoT nhỏ có bộ xử lý có khả năng chạy một máy ảo lớp SE nhưng chúng không nhất thiết phải có bộ nhớ để chứa tất cả JDK, đặc biệt, khi ứng dụng chỉ sử dụng một phần nhỏ của nó.
  • Nó thậm chí còn là một vấn đề trong Đám mây. Cloud là để tối ưu hóa việc sử dụng phần cứng, nếu bạn có hàng nghìn hình ảnh chứa toàn bộ JDK nhưng các ứng dụng chỉ sử dụng một phần nhỏ của nó thì thật lãng phí.

Mô-đun: Giải pháp chung

Để giải quyết các vấn đề trên, chúng tôi coi các mô-đun như một loại cấu phần chương trình Java mới cơ bản. Mô-đun là một tập hợp mã và dữ liệu được đặt tên, tự mô tả. Mã của nó được tổ chức như một tập hợp các gói chứa các kiểu, tức là, các lớp và giao diện Java; dữ liệu của nó bao gồm tài nguyên và các loại thông tin tĩnh khác.

Để kiểm soát cách mã của nó tham chiếu đến các loại trong các mô-đun khác, một mô-đun khai báo mô-đun nào khác mà nó yêu cầu để được biên dịch và chạy. Để kiểm soát cách mã trong các mô-đun khác tham chiếu đến các loại trong các gói của nó, một mô-đun khai báo gói nào trong số các gói đó mà nó xuất.

Hệ thống mô-đun định vị các mô-đun được yêu cầu và, không giống như cơ chế đường dẫn lớp, đảm bảo rằng mã trong một mô-đun chỉ có thể tham chiếu đến các loại trong các mô-đun mà nó phụ thuộc vào. Các cơ chế kiểm soát truy cập của ngôn ngữ Java và máy ảo Java ngăn mã truy cập vào các loại trong các gói không được xuất ra bởi các mô-đun xác định của chúng.

Ngoài việc đáng tin cậy hơn, mô-đun có thể cải thiện hiệu suất. Khi mã trong một mô-đun đề cập đến một loại trong một gói thì gói đó được đảm bảo sẽ được xác định trong mô-đun đó hoặc trong chính xác một trong các mô-đun được đọc bởi mô-đun đó. Do đó, khi tìm kiếm định nghĩa của một kiểu cụ thể, không cần phải tìm kiếm nó trong nhiều mô-đun hoặc tệ hơn, dọc theo toàn bộ đường dẫn lớp.

JEP cần theo dõi

Jigsaw là một dự án lớn đang diễn ra trong một vài năm. Nó có một lượng JEP ấn tượng, đây là những nơi tuyệt vời để có thêm thông tin về dự án. Một số JEP như sau:

  • JEP 200: JDK mô-đun : Sử dụng Hệ thống mô-đun nền tảng Java (JPMS) để mô-đun hóa JDK
  • JEP 201: Mã nguồn mô-đun : Tổ chức lại mã nguồn JDK thành các mô-đun, nâng cao hệ thống xây dựng để biên dịch mô-đun và thực thi ranh giới mô-đun tại thời điểm xây dựng
  • JEP 261: Hệ thống mô-đun : Triển khai Hệ thống mô-đun nền tảng Java, như được chỉ định bởi JSR 376, cùng với các thay đổi và cải tiến dành riêng cho JDK liên quan
  • JEP 220: Hình ảnh thời gian chạy mô-đun : Cơ cấu lại hình ảnh thời gian chạy JDK và JRE để phù hợp với các mô-đun và để cải thiện hiệu suất, bảo mật và khả năng bảo trì
  • JEP 260: Đóng gói hầu hết các API nội bộ : Làm cho hầu hết các API nội bộ của JDK không thể truy cập được theo mặc định nhưng để lại một số API nội bộ quan trọng, được sử dụng rộng rãi có thể truy cập được, cho đến khi tồn tại các thay thế được hỗ trợ cho tất cả hoặc hầu hết các chức năng của chúng
  • JEP 282: jlink: Trình liên kết Java : Tạo một công cụ có thể lắp ráp và tối ưu hóa một tập hợp các mô-đun và các phụ thuộc của chúng thành một hình ảnh thời gian chạy tùy chỉnh như được định nghĩa trong JEP 220

Đóng nhận xét

Trong ấn bản đầu tiên của báo cáo Trạng thái của Hệ thống mô-đun , Mark Reinhold mô tả các mục tiêu cụ thể của hệ thống mô-đun như sau:

  • Cấu hình đáng tin cậy , để thay thế cơ chế đường dẫn lớp dễ hỏng, dễ xảy ra lỗi bằng một phương tiện để các thành phần chương trình khai báo sự phụ thuộc rõ ràng vào nhau, cùng với
  • Tính đóng gói mạnh , để cho phép một thành phần khai báo loại công khai nào của nó có thể truy cập được đối với các thành phần khác và loại nào không.

Các tính năng này sẽ mang lại lợi ích trực tiếp cho các nhà phát triển ứng dụng, nhà phát triển thư viện và người triển khai Nền tảng Java SE và gián tiếp, vì chúng sẽ cho phép một nền tảng có thể mở rộng, tính toàn vẹn của nền tảng cao hơn và cải thiện hiệu suất.


3
Mark Reinhold là Kiến trúc sư trưởng của Nhóm Nền tảng Java tại Oracle, và câu trả lời này về cơ bản là câu trả lời trực tiếp của anh ấy cho câu hỏi chính xác đó.
Jay

1
Để bạn định lượng điều đó, HelloWorld có thể sử dụng 15 MB thay vì 553 MB; youtu.be/rFhhLXcOBsk?t=31m12s
user1133275

14

Để tranh luận, hãy khẳng định rằng Java 8 (và trước đó) đã có một "dạng" mô-đun (lọ) và hệ thống mô-đun (classpath). Nhưng có những vấn đề nổi tiếng với những điều này.

Bằng cách xem xét các vấn đề, chúng tôi có thể minh họa động lực cho Jigsaw. (Điều sau giả định rằng chúng tôi không sử dụng Mô-đun OSGi, JBoss, v.v., những mô-đun này chắc chắn cung cấp giải pháp.)

Vấn đề 1: công khai quá công khai

Hãy xem xét các lớp sau (giả sử cả hai đều là công khai):

com.acme.foo.db.api.UserDao
com.acme.foo.db.impl.UserDaoImpl

Tại Foo.com, chúng tôi có thể quyết định rằng nhóm của chúng tôi nên sử dụng UserDaovà không sử dụng UserDaoImpltrực tiếp. Tuy nhiên, không có cách nào để thực thi điều đó trên classpath.

Trong Jigsaw, một mô-đun có chứa một module-info.javatệp cho phép chúng ta trình bày rõ ràng những gì là công khai đối với các mô-đun khác. Đó là, công có sắc thái. Ví dụ:

// com.acme.foo.db.api.UserDao is accessible, but
// com.acme.foo.db.impl.UserDaoImpl is not 
module com.acme.foo.db {
    exports com.acme.foo.db.api;
}

Vấn đề 2: phản xạ là không thể kiềm chế

Với các lớp trong # 1, ai đó vẫn có thể làm điều này trong Java 8:

Class c = Class.forName("com.acme.foo.db.impl.UserDaoImpl");
Object obj = c.getConstructor().newInstance();

Điều đó có nghĩa là: phản xạ là mạnh mẽ và cần thiết, nhưng nếu không được kiểm soát, nó có thể được sử dụng để tiếp cận bên trong của một mô-đun theo những cách không mong muốn. Mark Reinhold có một ví dụ khá đáng báo động . (Bài SO ở đây .)

Trong Jigsaw, tính đóng gói mạnh cung cấp khả năng từ chối quyền truy cập vào một lớp, bao gồm cả phản xạ. (Điều này có thể phụ thuộc vào cài đặt dòng lệnh, đang chờ thông số kỹ thuật sửa đổi cho JDK 9.) Lưu ý rằng vì Jigsaw được sử dụng cho chính JDK, Oracle tuyên bố rằng điều này sẽ cho phép nhóm Java đổi mới nội bộ nền tảng nhanh hơn.

Vấn đề 3: classpath xóa các mối quan hệ kiến ​​trúc

Một nhóm thường có một mô hình tinh thần về mối quan hệ giữa các lọ. Ví dụ, foo-app.jarcó thể sử dụng foo-services.jarmà sử dụng foo-db.jar. Chúng tôi có thể khẳng định rằng các lớp trong foo-app.jarkhông nên bỏ qua "lớp dịch vụ" và sử dụng foo-db.jartrực tiếp. Tuy nhiên, không có cách nào để thực thi điều đó thông qua classpath. Mark Reinhold đề cập đến điều này ở đây .

Để so sánh, Jigsaw cung cấp một mô hình trợ năng rõ ràng, đáng tin cậy cho các mô-đun.

Vấn đề 4: Thời gian chạy nguyên khối

Thời gian chạy Java là nguyên khối rt.jar. Trên máy của tôi, nó là hơn 60 MB với 20k lớp! Trong thời đại của các dịch vụ vi mô, các thiết bị IoT, v.v., việc có Corba, Swing, XML và các thư viện khác trên đĩa là điều không mong muốn nếu chúng không được sử dụng.

Jigsaw tự chia nhỏ JDK thành nhiều mô-đun; ví dụ java.sql chứa các lớp SQL quen thuộc. Có một số lợi ích cho điều này, nhưng một cái mới là jlinkcông cụ. Giả sử một ứng dụng được mô-đun hóa hoàn toàn, hãy jlinktạo hình ảnh thời gian chạy có thể phân phối được cắt bớt để chỉ chứa các mô-đun được chỉ định (và các phần phụ thuộc của chúng). Nhìn về phía trước, Oracle hình dung ra một tương lai nơi các mô-đun JDK được biên dịch trước thời hạn thành mã gốc. Mặc dù jlinklà tùy chọn và việc biên dịch AOT là thử nghiệm, chúng là những dấu hiệu chính cho thấy vị trí của Oracle.

Vấn đề 5: Phiên bản

Rõ ràng là classpath không cho phép chúng ta sử dụng nhiều phiên bản của cùng một jar: ví dụ bar-lib-1.1.jarbar-lib-2.2.jar.

Jigsaw không giải quyết vấn đề này; Mark Reinhold nêu lý do ở đây . Ý chính là Maven, Gradle và các công cụ khác đại diện cho một hệ sinh thái lớn để quản lý sự phụ thuộc và một giải pháp khác sẽ có hại nhiều hơn là có lợi.

Cần lưu ý rằng các giải pháp khác (ví dụ OSGi) thực sự giải quyết được vấn đề này (và các giải pháp khác, ngoài # 4).

Kết luận

Đó là một số điểm chính của Jigsaw, được thúc đẩy bởi các vấn đề cụ thể.

Lưu ý rằng việc giải thích tranh cãi giữa các Mô-đun Jigsaw, OSGi, JBoss, v.v. là một cuộc thảo luận riêng biệt thuộc về một trang Stack Exchange khác. Có nhiều sự khác biệt giữa các giải pháp hơn được mô tả ở đây. Hơn nữa, đã có đủ sự đồng thuận để phê duyệt Phiếu Xem xét lại Công khai cho JSR 376.


3

Bài viết này giải thích chi tiết các vấn đề mà cả OSGi và JPMS / Jigsaw đều cố gắng giải quyết:

"Java 9, OSGi và tương lai của mô-đun" [22 SEP 2016]

Nó cũng đi sâu vào các cách tiếp cận của cả OSGi và JPMS / Jigsaw. Hiện tại, có vẻ như các tác giả đã liệt kê hầu như không có Ưu điểm thực tế nào cho JPMS / Jigsaw so với OSGi đã trưởng thành (16 tuổi).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.