ลำดับ
บทความนี้ส่วนใหญ่ศึกษาข้อควรระวังบางอย่างสำหรับการย้ายไปยัง Java9
ประเภทการย้ายถิ่น
1. รหัสไม่ใช่แบบแยกส่วนแรกย้ายไปยัง JDK9 เพื่อใช้ประโยชน์จาก API ของ JDK9
2. รหัสยังอพยพด้วยโมดูลาร์
บางสิ่งที่ควรทราบ
คลาสที่อ่านไม่ออก
ตัวอย่างเช่น sun.security.x509 จัดอยู่ในโมดูล java.base ใน Java9 แต่โมดูลไม่ได้ส่งออกแพ็คเกจ
คุณสามารถแก้ไขการตั้งค่าการส่งออกได้โดยเพิ่ม-เพิ่ม-ส่งออก java.base/sun.security.x509 = ทั้งหมดที่ไม่ได้ชื่อเมื่อทำงาน
ชั้นเรียนภายใน
ตัวอย่างเช่น sun.misc.unsafe เดิมต้องการใช้ทีม Oracle JDK แต่เนื่องจากคลาสเหล่านี้ใช้กันอย่างแพร่หลายมากเกินไป Java9 จึงประนีประนอมเพื่อให้เข้ากันได้ย้อนหลัง แต่จำแนกคลาสเหล่านี้ลงในโมดูล JDK
➜ ~ java -d jdk.unsupportedjdk.unsupported@9exports com.sun.nio.fileexports sun.miscexports sun.rectrequires java.base mandatedopens sun.miscopens sun.reflect
ชั้นเรียนที่ถูกลบ
java9 ลบ sun.misc.base64encoder ในกรณีนี้คุณสามารถใช้ API อื่น ๆ แทนเช่น java.util.base64
classpath vs โมดูลพา ธ
Java9 ได้แนะนำระบบโมดูลและ JDK ของตัวเองก็ถูกแยกออกจากกันและมีการแนะนำโมดูลพา ธ เพื่อบล็อก ClassPath กล่าวคือโมดูลพา ธ เป็นที่ต้องการใน Java9 ท้ายที่สุดแล้ว JDK เองก็เป็นโมดูลาร์ หากแอปพลิเคชันนั้นไม่ใช่โมดูลาร์ Java9 จะถูกปรับเป็นโมดูลโดยปริยายผ่านโมดูลที่ไม่มีชื่อและกลไกโมดูลอัตโนมัติ แน่นอนว่า classpath สามารถใช้กับ Java9 ต่อไปเช่นการใช้ Module-Path
ขวดที่ไม่มีโมดูลาร์จะถูกจัดประเภทเป็นโมดูลที่ไม่มีชื่อใน ClassPath; ใน Module-Path มันจะถูกสร้างขึ้นโดยอัตโนมัติเป็นโมดูลอัตโนมัติ (โมดูลอัตโนมัติจะประกาศว่าสกรรมกริยาขึ้นอยู่กับโมดูลที่มีชื่อและไม่มีชื่อทั้งหมดจากนั้นส่งออกแพ็คเกจของตัวเอง)
ชื่อแพ็คเกจไม่สามารถปรากฏในหลายโมดูล (แพ็คเกจแยก)
เนื่องจากสามารถระบุการส่งออกไปยังโมดูลอื่น ๆ ในโมดูลหากหลายโมดูลส่งออกชื่อแพ็คเกจเดียวกันมันจะทำให้เกิดความสับสน โดยเฉพาะอย่างยิ่งหากมีไลบรารีคลาสอื่น ๆ ที่ต้องการโมดูลทั้งสองนี้ในเวลาเดียวกันคุณไม่ทราบว่าควรอ้างอิงโมดูลใด
การพึ่งพาสกรรมกริยา
หากพารามิเตอร์อินเตอร์เฟสหรือประเภทการส่งคืนของโมดูลใช้คลาสของโมดูลอื่น ๆ ขอแนะนำให้ต้องใช้โมดูลสกรรมกริยาขึ้นอยู่กับ
ระวังการพึ่งพาแบบวงกลม
เมื่อออกแบบโมดูลให้พิจารณาว่าจะมีการพึ่งพาเป็นวงกลมให้มากที่สุดหรือไม่ ถ้าเป็นเช่นนั้นคุณต้องออกแบบใหม่
ใช้บริการเพื่อใช้การพึ่งพาเพิ่มเติม
บริการเหมาะอย่างยิ่งสำหรับการแยกการพึ่งพาของผู้โทรและคลาสการใช้งาน หากอินเทอร์เฟซมีคลาสการใช้งานหลายคลาสผู้โทรไม่จำเป็นต้องต้องการคลาสการใช้งานทั้งหมด แต่ต้องการเฉพาะอินเทอร์เฟซที่จำเป็นและใช้ประเภทบริการเพื่อโหลดอินสแตนซ์ของคลาสการใช้งาน Decoupling ทำได้โดยการเพิ่มโมดูลการใช้งานแบบไดนามิกในโมดูลพา ธ
การจัดการเวอร์ชันโมดูล
Module-info.java ไม่รองรับหมายเลขเวอร์ชันที่ประกาศ แต่เมื่อสร้างแพ็คเกจ JAR คุณสามารถตั้งค่าผ่าน-รุ่นโมดูล อย่างไรก็ตามเมื่อระบบโมดูลค้นหาโมดูลมันยังคงใช้ชื่อโมดูลเพื่อค้นหา (หากมีโมดูลซ้ำหลายโมดูลในโมดูลพา ธ ระบบโมดูลจะรู้ว่าใช้งานแรกที่พบและละเว้นโมดูลที่ตามมาโดยอัตโนมัติด้วยชื่อเดียวกัน) ปัญหาการพึ่งพาเวอร์ชันไม่ได้อยู่ในขอบเขตของโซลูชันของระบบโมดูลและถูกทิ้งให้อยู่กับเครื่องมือการจัดการการพึ่งพาเช่น Maven เพื่อจัดการ
การเข้าถึงทรัพยากรโมดูล
หลังจากการแยกส่วนไฟล์ทรัพยากรได้รับการปกป้องและโมดูลสามารถเข้าถึงไฟล์ทรัพยากรของโมดูลเท่านั้น หากจำเป็นต้องใช้การเข้าถึงข้ามโมดูลคุณต้องใช้ modulelayer เพื่อค้นหาโมดูลเป้าหมายแล้วเรียกโมดูลเป้าหมายเพื่อโหลดไฟล์ทรัพยากรของโมดูล
การใช้การสะท้อนกลับ
สิ่งนี้เกี่ยวข้องกับปัญหาการสะท้อนลึก การไตร่ตรองอย่างลึกซึ้งที่เรียกว่าการเรียกองค์ประกอบที่ไม่ใช่สาธารณะของชั้นเรียนผ่านการสะท้อน การส่งออกของ Module-info.java ประกาศว่าแพ็คเกจอนุญาตให้คลาสที่แพ็คเกจเป็นของโดยตรงเพื่อให้สามารถเข้าถึงองค์ประกอบสาธารณะและไม่อนุญาตให้มีการเรียกร้องให้มีการเรียกร้องให้มีการเรียกร้องให้มีองค์ประกอบที่ไม่ใช่สาธารณะ
การสะท้อนกลับต้องการการประกาศพิเศษที่จะได้รับอนุญาตในระบบโมดูล (โดยใช้การประกาศเปิดเพื่ออนุญาตให้มีการสะท้อนลึก) ซึ่งนำไปสู่ไลบรารีชั้นเรียนจำนวนมากที่ใช้การสะท้อนเช่นสปริงซึ่งต้องการการกำหนดค่าเพิ่มเติมเพื่อย้ายไปยัง Java9 มีสองวิธี: หนึ่งคือการเปิดชื่อแพ็คเกจไปยังโมดูลที่ต้องการการสะท้อนเช่น Spring.beans ฯลฯ ; อื่น ๆ คือการเปิดโมดูลทั้งหมดโดยตรง
ค่าเริ่มต้น-illegal-access = ใบอนุญาตและการตั้งค่านี้ใช้ได้เฉพาะกับแพ็คเกจก่อน Java9 ที่ไม่ได้รับอนุญาตให้เข้าถึงใน Java9 และไม่สามารถใช้ได้กับแพ็คเกจใหม่ที่ไม่ได้รับอนุญาตให้เข้าถึงใน Java9 (ขอแนะนำให้ตั้งค่าให้ปฏิเสธเมื่อย้ายไปยังระบบโมดูลาร์)
อย่างไรก็ตามในระบบโมดูลชื่อแพ็คเกจแตกต่างกันและไม่มีความสัมพันธ์ในการสืบทอด ตัวอย่างเช่น com.service.func1 และ com.service.func2 เป็นแพ็คเกจที่แตกต่างกัน คุณไม่สามารถเปิด com.service ได้ แต่คุณต้องระบุแยกต่างหากซึ่งนำไปสู่แพ็คเกจเพิ่มเติมที่ต้องเปิด ดังนั้นการเปิดโมดูลทั้งหมดอาจใช้งานง่ายกว่า แต่ก็เป็นวิธีที่ค่อนข้างหยาบวิธีการข้างต้นคือการเปลี่ยนแปลงในโมดูลดั้งเดิม-info.java อีกวิธีหนึ่งคือการปรับเปลี่ยนความสัมพันธ์ดั้งเดิมผ่านคำสั่งที่ระบุเมื่อดำเนินการ Java หรือ Javac ตัวอย่างเช่น
Java ...-ADD-OPENS Source Module/Source-Package = เป้าหมายโมดูล
หากคุณต้องการส่งออกไปยังโมดูลที่ไม่มีชื่อ
แน่นอนถ้าเป็นระบบใหม่ก็ไม่แนะนำให้ใช้การสะท้อน สามารถใช้ Methodhandles และ Varhandles ได้
คำถามที่พบบ่อยและมาตรการ
classnotfoundexception/noclassdeffounderror
ตัวอย่างเช่น javax.xml.bind.jaxbexception, Jaxb ได้รับการจัดประเภทเป็นโมดูล java.xml.bind และถูกเพิ่มหลังจากการตั้งชื่อ Java
-เพิ่มโมดูล java.xml.bind
หากคุณต้องการบันทึกปัญหาให้เพิ่ม $ java_home และไลบรารีของบุคคลที่สามทั้งหมดลงในโมดูลพา ธ แล้วทำ
-เพิ่มโมดูลทุกโมดูล
การเข้าถึงการสะท้อนแสงที่ผิดกฎหมายโดย XXX ไปยังวิธี java.lang.classloader.defineclass
สาเหตุการไตร่ตรองเนื่องจากระบบเก่าไม่มีโมดูล -info เพิ่มพารามิเตอร์ในการตั้งชื่อ Java และแก้ไข
-เพิ่ม-เปิด java.base/java.lang = all-unnamed
กำหนดโมดูลการพึ่งพา
การวิเคราะห์ผ่าน IDE หรือ JDEPS
jdeps -คลาส 'คลาส' คลาส/lib/*' -recursive -summary app.jar
JDEPS เป็นเพียงการวิเคราะห์รหัสแบบคงที่ หากมีคลาสที่ใช้การสะท้อนคุณไม่สามารถวิเคราะห์ได้ คุณต้องต้องการมันด้วยตนเอง หากการพึ่งพาเป็นทางเลือกคุณอาจต้องคงที่
ปัญหาความสามารถในการอ่านสำหรับการทดสอบหน่วยโมดูล
หากใช้โมดูลสำหรับการทดสอบหน่วยโมดูลทดสอบหน่วยสามารถได้รับความสามารถในการอ่านและความสามารถในการสะท้อนกลับของโมดูลเป้าหมายผ่าน-การส่งออกหรือ-เพิ่มขึ้นที่รันไทม์ นอกจากนี้เนื่องจากปัญหาแพคเกจแบบแยกชื่อแพ็คเกจของคลาสทดสอบหน่วยไม่สามารถทำซ้ำได้กับชื่อแพ็คเกจโมดูลเป้าหมาย ปรากฎว่าการทดสอบโครงการ Maven
สรุป
คุณสามารถย้ายไปที่ Java9 ได้ในสองขั้นตอน ก่อนอื่นคุณไม่ใช่โมดูลาร์ก่อนคุณจะใช้ JDK9 ก่อนเท่านั้น จากนั้นคุณเป็นโมดูลาร์