2012-01-20 12 views
7

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 JarRsrcLoaderRsrcURLStreamHandlerFactory 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

+0

bạn có đang chạy ứng dụng của bạn trong Equinox (container OSGi)? – Kane

+1

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

+0

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. –

Trả lời

11

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.URLgetURLStreamHandler 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 khai URLStreamHandler có tên com.company.product.protocol.rsrc.Handler sử dụng JarRsrcLoader, 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 trong RsrcURLStreamHandlerFactory 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 đó.

+0

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

+1

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 –

+0

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 đề đó. –

0

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:

  1. 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.

  2. 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.

  3. 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
  4. 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