ในที่ทำงานของฉันการกล่าวถึงเพียงคำว่า Xerces นั้นเพียงพอที่จะกระตุ้นความโกรธแค้นจากผู้พัฒนา ภาพรวมคร่าวๆของคำถาม Xerces อื่น ๆ เกี่ยวกับ SO ดูเหมือนจะบ่งบอกว่าผู้ใช้ Maven เกือบทั้งหมดนั้น "ถูก" โดยปัญหานี้ในบางจุด น่าเสียดายที่การเข้าใจปัญหาต้องใช้ความรู้เล็กน้อยเกี่ยวกับประวัติของ Xerces ...
ประวัติศาสตร์
Xerces เป็นตัวแยกวิเคราะห์ XML ที่ใช้กันอย่างแพร่หลายในระบบนิเวศ Java เกือบทุกไลบรารีหรือกรอบงานที่เขียนใน Java ใช้ Xerces ในบางความจุ
ขวด Xerces รวมอยู่ในไบนารีอย่างเป็นทางการจนถึงทุกวันนี้ ยกตัวอย่างเช่น Xerces 2.11.0 การดำเนินขวดเป็นชื่อและไม่
xercesImpl.jar
xercesImpl-2.11.0.jar
ทีม Xerces ไม่ได้ใช้ Mavenซึ่งหมายความว่าพวกเขาไม่ได้อัปโหลดปล่อยอย่างเป็นทางการเพื่อMaven กลาง
Xerces เคยถูกปล่อยออกมาเป็น jar เดียว (
xerces.jar
) แต่ถูกแบ่งออกเป็นสองขวดหนึ่งอันประกอบด้วย API (xml-apis.jar
) และอีกอันหนึ่งมีการใช้งานของ API เหล่านั้น (xercesImpl.jar
) รุ่นเก่าหลาย Mavenxerces.jar
ปอมยังคงประกาศการพึ่งพา เมื่อถึงจุดหนึ่งในอดีต Xerces ก็ได้รับการปล่อยตัวxmlParserAPIs.jar
ด้วยซึ่ง POM ที่มีอายุมากกว่าก็ขึ้นอยู่กับเวอร์ชันที่กำหนดให้กับขวด xml-apis และ xercesImpl โดยผู้ที่ปรับใช้ไหกับที่เก็บ Maven มักจะแตกต่างกัน ตัวอย่างเช่น xml-apis อาจได้รับรุ่น 1.3.03 และ xercesImpl อาจได้รับรุ่น 2.8.0 แม้ว่าทั้งสองจะมาจาก Xerces 2.8.0 นี่เป็นเพราะคนมักจะติดแท็กขวด xml-apis กับรุ่นของข้อกำหนดที่ใช้ มีความสุขมาก แต่ไม่สมบูรณ์รายละเอียดของที่นี่คือที่นี่
เพื่อทำให้เกิดความซับซ้อน Xerces คือตัวแยกวิเคราะห์ XML ที่ใช้ในการดำเนินการอ้างอิงของ Java API สำหรับการประมวลผล XML (JAXP) ซึ่งรวมอยู่ใน JRE คลาสการนำไปใช้งานถูกทำแพ็กเกจใหม่ภายใต้
com.sun.*
เนมสเปซซึ่งทำให้เป็นอันตรายต่อการเข้าถึงโดยตรงเนื่องจากอาจไม่มีอยู่ใน JREs บางตัว อย่างไรก็ตามฟังก์ชั่น Xerces บางส่วนนั้นไม่ได้เปิดเผยผ่านทางjava.*
และjavax.*
API ตัวอย่างเช่นไม่มี API ที่เปิดเผย Xerces ต่อเนื่องการเพิ่มความสับสนทำให้คอนเทนเนอร์ servlet เกือบทั้งหมด (JBoss, Jetty, Glassfish, Tomcat ฯลฯ ) มาพร้อมกับ Xerces ใน
/lib
โฟลเดอร์ของพวกเขาตั้งแต่หนึ่งตัวขึ้นไป
ปัญหาที่เกิดขึ้น
แก้ปัญหาความขัดแย้ง
สำหรับเหตุผลบางส่วนหรือทั้งหมดข้างต้นองค์กรจำนวนมากเผยแพร่และใช้งานการสร้างแบบกำหนดเองของ Xerces ใน POM ของพวกเขา นี่ไม่ใช่ปัญหาถ้าคุณมีแอปพลิเคชั่นขนาดเล็กและใช้ Maven Central เพียงอย่างเดียว แต่มันกลายเป็นปัญหาอย่างรวดเร็วสำหรับซอฟต์แวร์ระดับองค์กรที่ Artifactory หรือ Nexus กำลังพร็อกซีหลายแหล่งเก็บข้อมูล (JBoss, Hibernate ฯลฯ ):
ตัวอย่างเช่นองค์กร A อาจเผยแพร่xml-apis
เป็น:
<groupId>org.apache.xerces</groupId>
<artifactId>xml-apis</artifactId>
<version>2.9.1</version>
ในขณะเดียวกันองค์กร B อาจเผยแพร่เช่นเดียวjar
กับ:
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>1.3.04</version>
แม้ว่าบีjar
เป็นรุ่นที่ต่ำกว่าของ A jar
, Maven ไม่ทราบว่าพวกเขาเป็นสิ่งประดิษฐ์ที่เหมือนกันเพราะพวกเขามีความแตกต่างกัน
groupId
ของ ดังนั้นจึงไม่สามารถดำเนินการแก้ไขข้อขัดแย้งและทั้งสอง
jar
จะถูกรวมเป็นการอ้างอิงที่ได้รับการแก้ไข:
Classloader Hell
ดังกล่าวข้างต้น JRE มาพร้อมกับ Xerces ใน JAXP RI ในขณะที่มันเป็นการดีที่จะทำเครื่องหมาย Xerces Maven dependencies ทั้งหมดว่าเป็น<exclusion>
s หรือ as<provided>
รหัสบุคคลที่สามที่คุณใช้อาจขึ้นอยู่กับรุ่นที่ให้ไว้ใน JAXP ของ JDK ที่คุณใช้ นอกจากนี้คุณยังต้องจัดส่งขวด Xerces ในคอนเทนเนอร์ servlet ของคุณด้วย สิ่งนี้ทำให้คุณมีตัวเลือกมากมาย: คุณลบเวอร์ชันเซิร์ฟเล็ตและหวังว่าคอนเทนเนอร์ของคุณจะทำงานบนรุ่น JAXP หรือไม่ เป็นการดีกว่าที่จะออกจากเวอร์ชันเซิร์ฟเล็ตและหวังว่าเฟรมเวิร์กแอ็พพลิเคชันของคุณจะรันบนเวอร์ชันเซิร์ฟเล็ตหรือไม่? หากหนึ่งหรือสองของความขัดแย้งที่ยังไม่ได้แก้ไขที่ระบุไว้ข้างต้นจัดการเพื่อจัดส่งผลิตภัณฑ์ของคุณ (ง่ายต่อการเกิดขึ้นในองค์กรขนาดใหญ่) คุณจะพบว่าตัวเองอยู่ใน classloader นรกอย่างรวดเร็วสงสัยว่า Xerces รุ่นใด จะเลือก jar เดียวกันใน Windows และ Linux (อาจจะไม่ใช่)
การแก้ปัญหา?
เราได้พยายามทำเครื่องหมายทั้งหมดอ้างอิง Xerces Maven เป็น<provided>
หรือเป็น<exclusion>
แต่นี้เป็นเรื่องยากที่จะบังคับใช้ (โดยเฉพาะอย่างยิ่งกับทีมขนาดใหญ่) ที่กำหนดว่าสิ่งประดิษฐ์ที่มีชื่อแทนจำนวนมาก ( xml-apis
, xerces
, xercesImpl
, xmlParserAPIs
ฯลฯ ) นอกจากนี้ libs / framework ของบุคคลที่สามของเราอาจไม่ทำงานในรุ่น JAXP หรือรุ่นที่จัดทำโดยคอนเทนเนอร์ servlet
เราจะจัดการกับปัญหานี้ได้ดีที่สุดกับ Maven อย่างไร เราจำเป็นต้องใช้การควบคุมที่ละเอียดกว่านี้ขึ้นอยู่กับการพึ่งพาของเราหรือไม่จากนั้นพึ่งพาการทำ classloading แบบทำเป็นชั้น? มีวิธีใดบ้างในการที่จะยกเว้นการพึ่งพา Xerces ทั้งหมดและบังคับให้เฟรมเวิร์ก / libs ทั้งหมดของเราใช้เวอร์ชัน JAXP หรือไม่
อัปเดต : Joshua Spiewak ได้อัปโหลดสคริปต์การสร้าง Xerces build ไปยังXERCESJ-1454 รุ่นที่ได้รับการแก้ไขแล้วซึ่งอนุญาตให้อัพโหลดไปยัง Maven Central ได้ โหวต / เฝ้าดู / มีส่วนร่วมกับปัญหานี้และมาแก้ไขปัญหานี้ทันทีและสำหรับทั้งหมด