2010-03-30 18 views
49

में लोड की गई सभी कक्षाओं की एक सूची प्राप्त करें, मैं एक निश्चित पैकेज के साथ-साथ उनके सभी बच्चों के सभी वर्गों की एक सूची प्राप्त करना चाहता हूं। कक्षाएं पहले से ही JVM में लोड हो सकती हैं या नहीं भी हो सकती हैं।जावा - JVM

उत्तर

-1

ठीक है, मैंने जो किया वह क्लासपाथ में सभी फ़ाइलों को सूचीबद्ध कर रहा था। यह एक शानदार समाधान नहीं हो सकता है, लेकिन यह भरोसेमंद काम करता है और मुझे वह सब कुछ देता है जो मैं चाहता हूं, और भी बहुत कुछ।

+3

क्या आप कोड स्निपेट दे सकते हैं? इस तरह दूसरों को आपके समाधान से फायदा हो सकता है। धन्यवाद – jtzero

+5

@jtzero: मुझे नहीं पता कि ओपी क्या इस्तेमाल करता है, लेकिन मेरे लिए System.getProperty ("java.class.path") अच्छी तरह से काम करता है। –

+1

ओपी का क्या अर्थ है? परिचालक? ऑब्जेक्ट प्रोग्रामर? – hyprfrcb

89

यह एक कार्यक्रम संबंधी समस्या का समाधान नहीं है, लेकिन आप

java -verbose:class .... 

चला सकते हैं और JVM क्या यह लोड हो रहा है, और जहां से बाहर डंप हो जाएगा।

[Opened /usr/java/j2sdk1.4.1/jre/lib/rt.jar] 
[Opened /usr/java/j2sdk1.4.1/jre/lib/sunrsasign.jar] 
[Opened /usr/java/j2sdk1.4.1/jre/lib/jsse.jar] 
[Opened /usr/java/j2sdk1.4.1/jre/lib/jce.jar] 
[Opened /usr/java/j2sdk1.4.1/jre/lib/charsets.jar] 
[Loaded java.lang.Object from /usr/java/j2sdk1.4.1/jre/lib/rt.jar] 
[Loaded java.io.Serializable from /usr/java/j2sdk1.4.1/jre/lib/rt.jar] 
[Loaded java.lang.Comparable from /usr/java/j2sdk1.4.1/jre/lib/rt.jar] 
[Loaded java.lang.CharSequence from /usr/java/j2sdk1.4.1/jre/lib/rt.jar] 
[Loaded java.lang.String from /usr/java/j2sdk1.4.1/jre/lib/rt.jar] 

अधिक जानकारी के लिए here देखें।

2

आप क्लासलोडर के माध्यम से लोड की गई कक्षाओं की एक सूची प्राप्त करने में सक्षम हो सकते हैं लेकिन इसमें उन वर्गों को शामिल नहीं किया जाएगा जिन्हें आपने अभी तक लोड नहीं किया है लेकिन आपके क्लासपाथ पर हैं।

अपने क्लासपाथ पर सभी कक्षाएं प्राप्त करने के लिए आपको अपने दूसरे समाधान की तरह कुछ करना होगा। यदि आप वास्तव में कक्षाएं चाहते हैं जो वर्तमान में "लोड" हैं (दूसरे शब्दों में, कक्षाएं जिन्हें आपने पहले ही संदर्भित किया है, एक्सेस किया है या तत्काल किया है) तो आपको यह इंगित करने के लिए अपने प्रश्न को परिशोधित करना चाहिए।

import java.lang.instrument.ClassFileTransformer; 
import java.lang.instrument.IllegalClassFormatException; 
import java.security.ProtectionDomain; 

public class SimpleTransformer implements ClassFileTransformer { 

    public SimpleTransformer() { 
     super(); 
    } 

    public byte[] transform(ClassLoader loader, String className, Class redefiningClass, ProtectionDomain domain, byte[] bytes) throws IllegalClassFormatException { 
     System.out.println("Loading class: " + className); 
     return bytes; 
    } 
} 

यह दृष्टिकोण के अतिरिक्त लाभ है:

6

ऊपर वर्णित उन लोगों के लिए एक वैकल्पिक दृष्टिकोण का पता लगाना क्या वर्गों लोड किए गए हैं और -javaagent स्विच के साथ अपने कार्यक्रम चलाने के लिए java.lang.instrument का उपयोग कर एक बाहरी एजेंट बनाने के लिए किया जाएगा आपको क्लासलोडर ने दी गई कक्षा को लोड करने के बारे में जानकारी प्रदान की है।

6

मैं आपको यह भी सुझाव दूंगा कि आप -javagent एजेंट लिखें, लेकिन किसी भी कक्षा को बदलने के बजाय getAllLoadedClasses विधि का उपयोग करें।

अपने क्लाइंट कोड (सामान्य जावा कोड) के साथ सिंक्रनाइज़ करने के लिए, सॉकेट बनाएं और इसके माध्यम से एजेंट के साथ संवाद करें। फिर जब भी आपको आवश्यकता हो, तो आप "सभी वर्गों की सूची" विधि को ट्रिगर कर सकते हैं।

2

एक JRockit JVM के तहत अपने कोड चलाने, तो JRCMD <PID> print_class_summary

हो जाएगा ताकि उत्पादन सभी भरी हुई कक्षाएं, प्रत्येक पंक्ति में एक का उपयोग करें।

3

एक तरह से आप पहले से ही पैकेज शीर्ष स्तर पथ जानते हैं कि उपयोग करने के लिए OpenPojo

final List<PojoClass> pojoClasses = PojoClassFactory.getPojoClassesRecursively("my.package.path", null); 

तो फिर तुम सूची पर जाने के लिए और आप इच्छा किसी भी कार्यक्षमता प्रदर्शन कर सकते हैं है।

24

Reflections लाइब्रेरी का उपयोग कर, यह आसान है के रूप में:

Reflections reflections = new Reflections("my.pkg", new SubTypesScanner(false)); 

कि यूआरएल/s कि my.pkg पैकेज में शामिल में सभी वर्गों को स्कैन करेगा।

  • झूठी पैरामीटर का अर्थ है - ऑब्जेक्ट क्लास को बाहर न करें, जिसे डिफ़ॉल्ट रूप से बाहर रखा गया है।
  • कुछ परिदृश्यों (विभिन्न कंटेनर) में आप क्लासलोडर के साथ-साथ पैरामीटर भी पारित कर सकते हैं।

तो, सभी वर्गों में हो रही प्रभावी रूप से वस्तु के उपप्रकारों हो रही है, संक्रामक:।

Set<String> allClasses = 
    reflections.getStore().getSubTypesOf(Object.class.getName()); 

(साधारण तरीका reflections.getSubTypesOf(Object.class) PermGen में लोड हो रहा है सभी कक्षाओं का कारण होता है और शायद OutOfMemoryError फेंक आप डॉन यह नहीं करना चाहते हैं ...)

यदि आप सभी सीधे ऑब्जेक्ट (या किसी अन्य प्रकार) के उपप्रकार प्राप्त करना चाहते हैं, तो इसके सभी संक्रमणीय उपप्रकारों को बिना एक बार, इस का उपयोग करें:

Collection<String> directSubtypes = 
    reflections.getStore().get(SubTypesScanner.class).get(Object.class.getName()); 
+0

क्या प्रतिबिंब lib संस्करण का उपयोग कर रहे हैं? यह उदाहरण प्रतिबिंब 0.9.5 के साथ काम नहीं करता है। – pablosaraiva

+0

कभी नहीं, इसे प्रतिबिंबों का उपयोग करके काम कर रहा है-0.9.9-आरसी 1-uberjar – pablosaraiva

+1

आपको केवल उस पीड़ा से गुजरना है जो आपकी परियोजना में एक और लाइब्रेरी जोड़ रहा है। जावा में प्रश्न में भाषा होने पर आपको "आसान" शब्द का उपयोग करने की अनुमति नहीं है। आपने मुझे आशा दी कि यह मानक प्रतिबिंब है जो जेडीके का हिस्सा है। – ArtOfWarfare

10

इस प्रश्न का एकाधिक जवाब, आंशिक रूप से अस्पष्ट प्रश्न के कारण हैं - शीर्षक, JVM द्वारा भरी हुई कक्षाओं के बारे में बात कर रही है, जबकि प्रश्न की सामग्री कहते हैं, "या नहीं हो सकता जेवीएम द्वारा लोड किया गया "।

यह मानते हुए कि ओपी की जरूरत है कि किसी दिए गए classloader द्वारा JVM द्वारा लोड किए गए हैं कक्षाएं, और केवल उन्हीं वर्गों - मेरी जरूरत के रूप में अच्छी तरह से - वहाँ एक समाधान (elaborated here) है कि इस तरह चला जाता है:

import java.net.URL; 
import java.util.Enumeration; 
import java.util.Iterator; 
import java.util.Vector; 

public class CPTest { 

    private static Iterator list(ClassLoader CL) 
     throws NoSuchFieldException, SecurityException, 
     IllegalArgumentException, IllegalAccessException { 
     Class CL_class = CL.getClass(); 
     while (CL_class != java.lang.ClassLoader.class) { 
      CL_class = CL_class.getSuperclass(); 
     } 
     java.lang.reflect.Field ClassLoader_classes_field = CL_class 
       .getDeclaredField("classes"); 
     ClassLoader_classes_field.setAccessible(true); 
     Vector classes = (Vector) ClassLoader_classes_field.get(CL); 
     return classes.iterator(); 
    } 

    public static void main(String args[]) throws Exception { 
     ClassLoader myCL = Thread.currentThread().getContextClassLoader(); 
     while (myCL != null) { 
      System.out.println("ClassLoader: " + myCL); 
      for (Iterator iter = list(myCL); iter.hasNext();) { 
       System.out.println("\t" + iter.next()); 
      } 
      myCL = myCL.getParent(); 
     } 
    } 

} 

एक इसके बारे में साफ चीजों में से एक यह है कि आप एक मनमानी क्लासलोडर चुन सकते हैं जिसे आप देखना चाहते हैं। हालांकि यह तोड़ने की संभावना है कि क्लासलोडर वर्ग परिवर्तन के आंतरिक होना चाहिए, इसलिए इसे एक-ऑफ डायग्नोस्टिक टूल के रूप में उपयोग किया जाना है।

+0

@eis 'Thread.currentThread()। GetContextClassLoader()' बनाम 'CPTest.class.getClassLoader()' का उपयोग करने के बीच क्या अंतर है? क्या कोई कारण है कि आप 'थ्रेड' ऑब्जेक्ट से 'क्लासलोडर' प्राप्त करना पसंद करते हैं? –

+0

@MichaelPlautz अंतर यह है कि दूसरा धागा संदर्भ वर्ग लोडर है और दूसरा वर्ग वर्ग द्वारा उपयोग किया जाने वाला वर्ग लोडर है। जावा द्वारा उपयोग किए जाने वाले कई अलग-अलग क्लासलोडर हैं, जिन्हें मैं इस टिप्पणी स्थान में विस्तारित नहीं करूंगा। इसका कारण यह है कि यह माना जाता है कि थ्रेड संदर्भ क्लासलोडर अभिभावक संबंध में पूरे JVM शामिल होंगे, जबकि क्लास क्लासलोडर शायद नहीं। – eis

+0

आप 'ClassLoader.class.getDeclaredField (" कक्षाएं ") कर रहे हैं 'लूप' से बच सकते हैं। – metasim

0

यह प्रोग्राम सभी वर्गों को अपने भौतिक पथ से प्रिंट करेगा। यदि आप किसी भी वेब/एप्लिकेशन सर्वर से कक्षा लोडिंग का विश्लेषण करने की आवश्यकता है तो इसका उपयोग किसी भी जेएसपी को कॉपी कर सकते हैं।

import java.lang.reflect.Field; 
import java.util.Vector; 

public class TestMain { 

    public static void main(String[] args) { 
     Field f; 
     try { 
      f = ClassLoader.class.getDeclaredField("classes"); 
      f.setAccessible(true); 
      ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 
      Vector<Class> classes = (Vector<Class>) f.get(classLoader); 

      for(Class cls : classes){ 
       java.net.URL location = cls.getResource('/' + cls.getName().replace('.', 
       '/') + ".class"); 
       System.out.println("<p>"+location +"<p/>"); 
      } 
     } catch (Exception e) { 

      e.printStackTrace(); 
     } 
    } 
} 
संबंधित मुद्दे

 संबंधित मुद्दे