2009-06-03 23 views
30

Có cách nào để xác định các lớp nào được tải từ các jars nào khi chạy không?Cách khám phá những lớp nào được tải từ JAR nào?

Tôi chắc chắn tất cả chúng ta đã ở trong địa ngục JAR trước đây. Tôi đã chạy qua vấn đề này rất nhiều xử lý sự cố ClassNotFoundException s và NoClassDefFoundError s về các dự án. Tôi muốn tránh tìm tất cả các trường hợp của một lớp trong lọ và sử dụng quy trình loại bỏ trên mã khiến CNFE tìm ra thủ phạm.

Mọi công cụ quản lý hoặc hồ sơ có cung cấp cho bạn loại thông tin này không?

Vấn đề này cực kỳ khó chịu vì chúng tôi cần có thông tin này vào thời điểm lớp được tải. Có phải là một cách để có được nó, hoặc ghi lại nó và tìm thấy nó, nhưng tôi biết không có gì mà sẽ làm điều này, phải không?

Tôi biết OSGi và các gói/mô-đun được phiên bản nhằm mục đích làm cho vấn đề này không thành vấn đề ... nhưng dường như nó không biến mất sớm. :)

LƯU Ý: Tôi tìm thấy điều này question là một tập con của câu hỏi của tôi liên quan đến các lớp được tải từ các lọ được phiên bản.

Cập nhật: Hơi liên quan, bài đăng này giải thích một chiến lược tìm kiếm một lớp trong lọ (hoặc trong thư mục hiện tại) hoặc trong M2_REPO của bạn. JarScan, scan all JAR files in all subfolders for specific class

Cập nhật 2: Cũng hơi liên quan, JBoss Tattletale

+0

Jason Day có quyền, về cơ bản đây là bản sao của câu hỏi tôi đã hỏi cách đây không lâu. http://stackoverflow.com/questions/779650/where-on-the-file-system-was-my-java-class-loaded-from – shsteimer

Trả lời

56

Đi qua các -verbose:class chuyển sang lệnh java sẽ in mỗi lớp được nạp và nơi mà nó đã được nạp từ.

Joops cũng là một công cụ tốt để tìm các lớp bị thiếu trước thời hạn.

+2

Tôi vừa thử -verbose: tùy chọn lớp. Nó thật tuyệt!!! Thực sự hữu ích thực sự hữu ích – OscarRyz

+0

Rất tốt - Các vòng lặp trông rất tuyệt - bạn có biết nó đủ thông minh để theo một lớp được tham chiếu thông qua Class.forName không? – cwash

+0

Tôi sẽ ngạc nhiên nếu nó có thể làm theo tham chiếu Class.forName, nhưng tôi không biết chắc chắn. Joops cũng có lệnh 'which', vì vậy bạn có thể sử dụng lệnh đó để kiểm tra các lớp theo cách thủ công. –

14

Từ mã bạn có thể gọi:

myObject.getClass().getProtectionDomain().getCodeSource() 

(Lưu ý, getProtectionDomain có thể không may trở null (thiết kế xấu), vì vậy "mã đúng" sẽ kiểm tra cho điều đó.)

+0

Điều này sẽ không giúp với CNFE hoặc NCDFE; khi bạn đã làm điều này? – cwash

+0

Có lẽ nếu bạn nhận được một ClassNotFoundException thì bạn có lẽ đã biết lớp không nằm trong bất kỳ lọ nào. (Giả sử bạn không chơi với trình nạp lớp.) Có thể có vấn đề nếu có các lỗi khác trong quá trình tải lớp, như một lớp cha bị thiếu. –

+0

@ TomHawtin-tackline bạn có thể nhận 'ClassNotFoundException' nếu một trình khởi tạo tĩnh của lớp đã nói sẽ ném một ngoại lệ. Sau đó, bạn có lớp trong tệp jar, nhưng ClassLoader không thể tải nó. – hidralisk

4

Có một MBean cho cờ JVM được đề cập bởi Jason Day ở trên.

Nếu bạn đang sử dụng JBoss, bạn có thể điều chỉnh theo yêu cầu bằng JMX, nếu bạn thêm máy chủ JMX MBean gốc vào cấu hình của mình. Thêm những thứ sau đây -D's:

-Dcom.sun.management.jmxremote.port=3333 
-Dcom.sun.management.jmxremote.authenticate=false 
-Dcom.sun.management.jmxremote.ssl=false 
-Djboss.platform.mbeanserver 
-Djavax.management.builder.initial=org.jboss.system.server.jmx.MBeanServerBuilderImpl 
-DJBOSS_CLASSPATH="../lib/jboss-system-jmx.jar" 

Và sau đó bạn có thể thấy cài đặt này trong java.lang: Classloading MBean và có thể cắt bật/tắt khi đang di chuyển. Điều này là hữu ích nếu bạn chỉ muốn nó trên trong khi thực hiện một đoạn mã nhất định.

Ngoài ra còn có một MBean cho phép bạn nhập tên lớp đủ điều kiện và xem vị trí được tải từ phân cấp lớp. MBean được gọi là LoaderRepository và bạn sẽ muốn gọi hoạt động displayClassInfo(), truyền vào FQCN.

0

Trong WebSphere (WS), bạn có thể sử dụng một tính năng gọi là "Class Loader Viewer"

Enable người xem lớp nạp đầu tiên bằng cách nhấn Servers> Các loại Server> máy chủ ứng dụng WebSphere> SERVER_NAME> dịch vụ xem lớp loader, kích hoạt dịch vụ và khởi động lại máy chủ.

Sau đó, bạn có thể đi tới Khắc phục sự cố> Trình xem trình tải lớp và tìm kiếm tên lớp hoặc tên gói của bạn.

https://www-01.ibm.com/support/knowledgecenter/SSAW57_8.5.5/com.ibm.websphere.nd.doc/ae/ttrb_classload_viewer.html?lang=en

0

Bạn có thể dễ dàng xuất khẩu một hoạt động JMX để truy cập thông tin trọn gói cho bất kỳ lớp được nạp trong khi chế biến như:

public static final class Jmx { 

    @JmxExport 
    public static Reflections.PackageInfo getPackageInfo(@JmxExport("className") final String className) { 
     return Reflections.getPackageInfo(className); 
    } 
    } 

và đây là một thử nghiệm đơn vị đơn giản để xuất khẩu và gọi nó:

@Test 
    public void testClassLocator() throws IOException, InstanceNotFoundException, MBeanException, ReflectionException { 
    Registry.export(Jmx.class); 
    Reflections.PackageInfo info = (Reflections.PackageInfo) Client.callOperation(
      "service:jmx:rmi:///jndi/rmi://:9999/jmxrmi", 
      Jmx.class.getPackage().getName(), 
      Jmx.class.getSimpleName(), "getPackageInfo", Registry.class.getName()); 
    System.out.println(info); 
    Assert.assertNotNull(info); 
    } 

đây là tất cả dựa trên một số thư viện tiện ích nhỏ từ spf4j (http://www.spf4j.org)

bạn có thể thấy mã này at và kiểm tra at

Các vấn đề liên quan