Trong văn phòng của tôi, chỉ cần nhắc đến từ Xerces là đủ để kích động cơn thịnh nộ giết người từ các nhà phát triển. Nhìn lướt qua các câu hỏi Xerces khác về SO dường như chỉ ra rằng hầu như tất cả người dùng Maven đều "cảm động" bởi vấn đề này tại một số điểm. Thật không may, hiểu được vấn đề đòi hỏi một chút kiến thức về lịch sử của Xerces ...
Lịch sử
Xerces là trình phân tích cú pháp XML được sử dụng rộng rãi nhất trong hệ sinh thái Java. Hầu như mọi thư viện hoặc khung được viết bằng Java đều sử dụng Xerces trong một số khả năng (liên tục, nếu không trực tiếp).
Các lọ Xerces có trong các tệp nhị phân chính thức , cho đến ngày nay, không được phiên bản. Ví dụ, jar triển khai Xerces 2.11.0 được đặt tên
xercesImpl.jar
và khôngxercesImpl-2.11.0.jar
.Nhóm Xerces không sử dụng Maven , điều đó có nghĩa là họ không tải lên bản phát hành chính thức lên Maven Central .
Xerces từng được phát hành dưới dạng một jar (
xerces.jar
), nhưng được chia thành hai lọ, một lọ chứa API (xml-apis.jar
) và một lọ chứa các triển khai của các API đó (xercesImpl.jar
). Nhiều Paven Maven cũ vẫn tuyên bố một sự phụ thuộc vàoxerces.jar
. Tại một số thời điểm trong quá khứ, Xerces cũng được phát hànhxmlParserAPIs.jar
, điều mà một số POM cũ cũng phụ thuộc vào.Các phiên bản được gán cho các lọ xml-apis và xercesImpl bởi những người triển khai các lọ của họ vào kho lưu trữ Maven thường khác nhau. Ví dụ: xml-apis có thể được cung cấp phiên bản 1.3.03 và xercesImpl có thể được cung cấp phiên bản 2.8.0, mặc dù cả hai đều từ Xerces 2.8.0. Điều này là do mọi người thường gắn thẻ jar xml-apis với phiên bản của thông số kỹ thuật mà nó thực hiện. Có một sự cố rất tốt, nhưng không đầy đủ về điều này ở đây .
Để làm phức tạp vấn đề, Xerces là trình phân tích cú pháp XML được sử dụng trong triển khai tham chiếu API Java để xử lý XML (JAXP), được bao gồm trong JRE. Các lớp thực hiện được đóng gói lại trong
com.sun.*
không gian tên, điều này gây nguy hiểm khi truy cập trực tiếp vào chúng, vì chúng có thể không có sẵn trong một số JRE. Tuy nhiên, không phải tất cả các chức năng của Xerces đều được thể hiện thông quajava.*
vàjavax.*
API; ví dụ: không có API nào hiển thị tuần tự hóa Xerces.Thêm vào mớ hỗn độn khó hiểu, hầu hết tất cả các thùng chứa servlet (JBoss, Jetty, Glassfish, Tomcat, v.v.), đều gửi Xerces trong một hoặc nhiều
/lib
thư mục của họ .
Các vấn đề
Giải quyết xung đột
Đối với một số - hoặc có lẽ là tất cả - về các lý do trên, nhiều tổ chức xuất bản và sử dụng các bản dựng Xerces tùy chỉnh trong POM của họ. Đây thực sự không phải là vấn đề nếu bạn có một ứng dụng nhỏ và chỉ sử dụng Maven Central, nhưng nó nhanh chóng trở thành vấn đề đối với phần mềm doanh nghiệp nơi Artifactory hoặc Nexus đang ủy quyền nhiều kho lưu trữ (JBoss, Hibernate, v.v.):
Ví dụ: tổ chức A có thể xuất bản xml-apis
dưới dạng:
<groupId>org.apache.xerces</groupId>
<artifactId>xml-apis</artifactId>
<version>2.9.1</version>
Trong khi đó, tổ chức B có thể xuất bản giống jar
như:
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>1.3.04</version>
Mặc dù B's jar
là phiên bản thấp hơn A jar
, nhưng Maven không biết rằng chúng là cùng một vật phẩm vì chúng có groupId
s khác nhau
. Do đó, nó không thể thực hiện giải quyết xung đột và cả hai
jar
sẽ được đưa vào dưới dạng các phụ thuộc đã giải quyết:
Lớp học địa ngục
Như đã đề cập ở trên, các tàu JRE có Xerces trong JAXP RI. Mặc dù thật tuyệt khi đánh dấu tất cả các phụ thuộc <exclusion>
của Xerces Maven là s hoặc như<provided>
, mã của bên thứ ba mà bạn phụ thuộc có thể hoặc không thể hoạt động với phiên bản được cung cấp trong JAXP của JDK mà bạn đang sử dụng. Ngoài ra, bạn có các lọ Xerces được vận chuyển trong thùng chứa servlet của bạn để tranh đấu. Điều này cho bạn một số lựa chọn: Bạn có xóa phiên bản servlet và hy vọng rằng container của bạn chạy trên phiên bản JAXP không? Có tốt hơn khi rời khỏi phiên bản servlet và hy vọng rằng các khung ứng dụng của bạn chạy trên phiên bản servlet không? Nếu một hoặc hai trong số các xung đột chưa được giải quyết được nêu ở trên có thể xâm nhập vào sản phẩm của bạn (dễ xảy ra trong một tổ chức lớn), bạn sẽ nhanh chóng thấy mình trong địa ngục của trình tải lớp, tự hỏi phiên bản nào của trình tải lớp Xerces đang chọn trong thời gian chạy và liệu nó có hay không sẽ chọn cùng một jar trong Windows và Linux (có thể không).
Các giải pháp?
Chúng tôi đã cố gắng đánh dấu tất cả phụ thuộc Xerces Maven như <provided>
hoặc như một <exclusion>
, nhưng điều này rất khó thực thi (đặc biệt là với một đội bóng lớn) cho rằng các hiện vật có rất nhiều bí danh ( xml-apis
, xerces
, xercesImpl
, xmlParserAPIs
, vv). Ngoài ra, các lib / khung bên thứ ba của chúng tôi có thể không chạy trên phiên bản JAXP hoặc phiên bản được cung cấp bởi một thùng chứa servlet.
Làm thế nào chúng ta có thể giải quyết tốt nhất vấn đề này với Maven? Chúng ta có phải thực hiện kiểm soát chi tiết như vậy đối với các phụ thuộc của chúng ta, và sau đó dựa vào tải lớp không? Có cách nào để loại trừ toàn bộ tất cả các phụ thuộc của Xerces và buộc tất cả các khung / lib của chúng tôi sử dụng phiên bản JAXP không?
CẬP NHẬT : Joshua Spiewak đã tải lên một phiên bản vá của các tập lệnh xây dựng Xerces lên XERCESJ-1454 cho phép tải lên Maven Central. Bình chọn / xem / đóng góp cho vấn đề này và chúng ta hãy khắc phục vấn đề này một lần và mãi mãi.