Tôi đang phát triển một ứng dụng web bằng cách sử dụng một jar thực thi với Jetty được nhúng.
Bình của tôi chứa lọ phụ thuộc (jar trong lọ)
Tôi đã tham chiếu đến JarRsrcLoader
và RsrcURLStreamHandlerFactory
do Eclipse phát triển.
JarRsrcLoader
đang sử dụng URL#setURLStreamHandlerFactory(RsrcURLStreamHandlerFactory)
để giải quyết giao thức rsrc
.
Qua đó, nó có thể giải quyết đường dẫn lớp cho jar.
Nhưng nó trở thành không thể giải quyết các giao thức thông thường như tác dụng phụ.
ví dụ: file:xxxx
hoặc jar:xxxx
.
RsrcURLStreamHandlerFactory
có phương thức setURLStreamHandlerFactory
.
Có lẽ tôi nghĩ tôi nên đặt cài đặt mặc định cho phương thức này.
Tôi không biết điều gì đã đặt phương thức này.URL.setURLStreamHandlerFactory
Trả lời
Chỉ có một phiên bản thực thi URLStreamHandlerFactory
được đăng ký trong thời gian chạy Java, vì vậy việc triển khai này phải được nhận thức của tất cả các giao thức được hỗ trợ.
Hành vi mặc định của Oracle/Sun không được triển khai theo cách đó nhưng trực tiếp trong lớp java.net.URL
. Vì vậy, bạn không thể chỉ đơn giản là tiêm thực hiện mặc định như là một nhà máy xích trong RsrcURLStreamHandlerFactory
. Phần đầu của câu trả lời.
Phương pháp java.net.URL
getURLStreamHandler
tải một thực hiện cho một giao thức X
theo chính sách đặt tên của tên lớp của nó, theo mặc định như sun.net.www.protocol.X.Handler
Nếu bạn nhìn vào jre/lib/rt.jar
, bạn sẽ tìm thấy:
sun/net/www/protocol/ftp/Handler.class
sun/net/www/protocol/gopher/Handler.class
sun/net/www/protocol/mailto/Handler.class
sun/net/www/protocol/netdoc/Handler.class
sun/net/www/protocol/http/Handler.class
sun/net/www/protocol/jar/Handler.class
sun/net/www/protocol/file/Handler.class
Danh sách các gói cơ sở được sử dụng cho giao thức URLStreamHandler
lựa chọn đến từ thuộc tính hệ thống Java java.protocol.handler.pkgs
. Tôi mời bạn đọc mã nguồn đầy đủ của số java/net/URL.java
từ JDK src.zip
để hiểu chi tiết.
Vì vậy, đúng cách để làm điều đó (bất kể IBM/Eclipse đã làm) là để lại cơ chế mặc định tại chỗ và thiết lập ví dụ
-Djava.protocol.handler.pkgs="com.company.product.protocol"
trên dòng lệnh (nếu bạn được phép/chứng nhận để làm như vậy) . Với triển khaiURLStreamHandler
có têncom.company.product.protocol.rsrc.Handler
sử dụngJarRsrcLoader
, bạn hoàn thành công việc.Lựa chọn thay thế là để viết một thi
URLStreamHandlerFactory
như một nhà máy bị xích trongRsrcURLStreamHandlerFactory
lấy cảm hứng từURL.getURLStreamHandler
mã nguồn. Ví dụ: bạn có thể đọc this old JBoss code. Nó dựa trên bộ nhớ cache bộ xử lý nội bộURL
bằng cách tải trước các giao thức đã biết (hoặc đã sử dụng) trước khi đăng ký nhà máy. Theo tôi, chỉ xấu xí thôi.
Warning: RsrcURLStreamHandler
đã thay thế bản gốc 180-đường-of-mã của URLStreamHandler.parseURL
bằng cách riêng của mình 10-dòng "phiên bản" mà không gọi super.parseURL
. Để chắc chắn nó không tôn trọng các đặc tả nối URL! Hãy cẩn thận, bạn có thể gặp lỗi tùy thuộc vào cách sử dụng các URL đó.
Cảm ơn bạn đã tham khảo mã JBoss cũ. Tôi thực sự sử dụng nó một và tôi đã ngạc nhiên khi tôi phải thêm cuộc gọi đến 'URL.setURLStreamHandlerFactory()' khi tôi bắt đầu JBosss microcontainer (để chạy JUnit). :-) – alexsmail
Không đúng khi cài đặt URLStreamHandlerFactory cần biết tất cả các giao thức, nó có thể trả về "null" và lớp URL sẽ thử các nguồn khác. Vấn đề duy nhất với phương pháp tiếp cận nhà máy hiện tại là, nó chỉ có thể được đăng ký một lần và tất cả những thứ khác cần phải dự phòng cho thuộc tính hệ thống hoặc khác. Thiết kế khá xấu. http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7u40-b43/java/net/URL.java#URL.getURLStreamHandler%28java.lang.String%29 –
Tôi không thể xác nhận trên các phiên bản Java và Eclipse mà các cuộc điều tra này đã được thực hiện ... nhưng tôi đoán hành vi rỗng-to-default-fallback này là một thay đổi "gần đây" để giải quyết vấn đề đó. –
Tính đến Java 9 bạn có thể sử dụng SPI để cung cấp xử lý:
URL(String, String, int, String) constructor javadoc thuật toán mô tả tìm kiếm:
Nếu trước đây các ứng dụng đã thiết lập một thể hiện của URLStreamHandlerFactory như suối nhà máy xử lý, sau đó phương thức createURLStreamHandler của cá thể đó được gọi với chuỗi giao thức làm đối số để tạo trình xử lý giao thức luồng.
Nếu không URLStreamHandlerFactory vẫn chưa được thiết lập, hoặc nếu phương pháp createURLStreamHandler của nhà máy trả về null, sau đó cơ chế ServiceLoader được sử dụng để xác định vị trí URLStreamHandlerProvider hiện thực bằng cách sử dụng bộ nạp lớp hệ thống. Thứ tự mà các nhà cung cấp được đặt là triển khai cụ thể và việc triển khai sẽ miễn phí để lưu trữ các nhà cung cấp định vị. Một ServiceConfigurationError, Error hoặc RuntimeException được ném ra từ createURLStreamHandler, nếu gặp phải, sẽ được truyền tới luồng gọi. Phương thức createURLStreamHandler của mỗi nhà cung cấp, nếu được khởi tạo, được gọi, với chuỗi giao thức, cho đến khi nhà cung cấp trả về không null hoặc tất cả các nhà cung cấp đã bị cạn kiệt.
- Nếu bước trước thất bại trong việc tìm một xử lý giao thức, các nhà xây dựng sẽ đọc giá trị tài sản của hệ thống: java.protocol.handler.pkgs
- Nếu bước trước thất bại trong việc tìm một xử lý giao thức, sau đó các nhà xây dựng cố gắng tải trình xử lý giao thức được tích hợp sẵn. Nếu lớp này không tồn tại, hoặc nếu lớp tồn tại nhưng nó không phải là một lớp con của URLStreamHandler, thì một MalformedURLException được ném ra.
xử lý giao thức cho các giao thức sau được đảm bảo để tồn tại trên con đường tìm kiếm: http, https, tập tin, và jar
bạn có đang chạy ứng dụng của bạn trong Equinox (container OSGi)? – Kane
Thật kỳ lạ. "tệp" được JRE triển khai, JRE nên tìm kiếm trong gói của nó nếu nhà máy của bạn không biết 'tệp'. Xem URL.getURLStreamHandler() hoặc gỡ lỗi. – Kane
Tôi đồng ý. Chúng tôi có thể xem xét URL.getURLStreamHandler là "lạ". Nhà máy có ưu tiên so với các giao thức khác, trừ khi một trình xử lý đã có trong bộ nhớ cache của nó. Thật kỳ lạ, ít nhất là không nhất quán. –