Java Language
Classloaders
खोज…
टिप्पणियों
एक क्लास लोडर एक ऐसा वर्ग है जिसका प्राथमिक उद्देश्य किसी एप्लिकेशन द्वारा उपयोग की जाने वाली कक्षाओं के स्थान और लोडिंग का मध्यस्थता करना है। एक क्लास लोडर भी संसाधनों को ढूंढ और लोड कर सकता है।
मानक क्लास लोडर कक्षाएं फ़ाइल सिस्टम में निर्देशिकाओं और JAR और ज़िप फ़ाइलों से कक्षाओं और संसाधनों को लोड कर सकती हैं। वे एक दूरस्थ सर्वर से JAR और ZIP फ़ाइलों को डाउनलोड और कैश भी कर सकते हैं।
क्लास लोडर सामान्य रूप से जंजीरदार होते हैं, ताकि जेवीएम आवेदन-प्रदत्त स्रोतों की प्राथमिकता में मानक कक्षा पुस्तकालयों से कक्षाएं लोड करने का प्रयास करेगा। कस्टम क्लास लोडर प्रोग्रामर को इसे बदलने की अनुमति देते हैं। यह भी इस तरह के काम कर सकते हैं जैसे कि डिक्रिप्टिंग फाइल और बायटेकोड मॉडिफिकेशन।
त्वरित और क्लास लोडर का उपयोग करना
यह मूल उदाहरण दिखाता है कि कोई एप्लिकेशन किसी क्लास लोडर को कैसे इंस्टेंट कर सकता है और इसका उपयोग क्लास को गतिशील रूप से लोड करने के लिए कर सकता है।
URL[] urls = new URL[] {new URL("file:/home/me/extras.jar")};
Classloader loader = new URLClassLoader(urls);
Class<?> myObjectClass = loader.findClass("com.example.MyObject");
इस उदाहरण में बनाए गए क्लास-लोडर में उसके माता-पिता के रूप में डिफ़ॉल्ट क्लास-लोडर होगा, और "extra.jar" में देखने से पहले पैरेंट क्लास-लोडर में किसी भी वर्ग को खोजने का प्रयास करेगा। यदि अनुरोधित वर्ग पहले ही लोड हो चुका है, तो findClass
कॉल पहले से लोड किए गए वर्ग के संदर्भ को वापस कर देगा।
findClass
कॉल विभिन्न तरीकों से विफल हो सकती है। सबसे आम हैं:
- यदि नामित वर्ग नहीं मिल सकता है, तो
ClassNotFoundException
साथ कॉल करें। - यदि नामित वर्ग किसी अन्य वर्ग पर निर्भर करता है जो नहीं मिल सकता है, तो कॉल
NoClassDefFoundError
फेंक देगा।
एक कस्टम classLoader लागू करना
प्रत्येक कस्टम लोडर को सीधे या परोक्ष रूप से java.lang.ClassLoader
वर्ग का विस्तार करना चाहिए। मुख्य विस्तार बिंदु निम्न विधियाँ हैं:
-
findClass(String)
- यदि आपका क्लास लोडर क्लास लोडिंग के लिए मानक डेलिगेशन मॉडल का अनुसरण करता है, तो इस विधि को अधिभारित करें। -
loadClass(String, boolean)
- एक वैकल्पिक प्रतिनिधिमंडल मॉडल को लागू करने के लिए इस विधि को अधिभारित करें। -
findResource
औरfindResources
- संसाधन लोडिंग को अनुकूलित करने के लिए इन विधियों को अधिभारित करें।
defineClass
तरीके जो वास्तव में बाइट सरणी से क्लास को लोड करने के लिए जिम्मेदार हैं, ओवरलोडिंग को रोकने के लिए final
हैं। defineClass
को कॉल करने से पहले किसी भी कस्टम व्यवहार को करने की आवश्यकता है।
यहाँ एक सरल है जो एक विशिष्ट वर्ग को बाइट सरणी से लोड करता है:
public class ByteArrayClassLoader extends ClassLoader {
private String classname;
private byte[] classfile;
public ByteArrayClassLoader(String classname, byte[] classfile) {
this.classname = classname;
this.classfile = classfile.clone();
}
@Override
protected Class findClass(String classname) throws ClassNotFoundException {
if (classname.equals(this.classname)) {
return defineClass(classname, classfile, 0, classfile.length);
} else {
throw new ClassNotFoundException(classname);
}
}
}
चूँकि हमने केवल findClass
मेथड को ओवरराइड किया है, इसलिए यह कस्टम क्लास लोडर loadClass
निम्नानुसार व्यवहार करने loadClass
है।
-
loadClass
कीloadClass
विधि कॉलfindLoadedClass
यह देखने के लिए कि क्या इस नाम के साथ एक वर्ग पहले से ही इस लोडर द्वारा लोड किया गया है। यदि वह सफल होता है, तो परिणामीClass
ऑब्जेक्ट अनुरोधकर्ता को वापस कर दी जाती है। -
loadClass
विधि फिर इसकेloadClass
कॉल को कॉल करके पैरेंटloadClass
। यदि माता-पिता अनुरोध के साथ सौदा कर सकते हैं, तो यह एकClass
ऑब्जेक्ट वापस करेगा जो फिर अनुरोधकर्ता को वापस कर दिया जाता है। - यदि पैरेंट क्लास
findClass
क्लास को लोड नहीं कर सकता है, तोfindClass
फिर हमारे ओवरराइडfindClass
मेथड को कॉल करता है, क्लास का नाम लोड किया जा रहा है। - अनुरोध किया नाम से मेल खाता है
this.classname
, हम फोनdefineClass
से वास्तविक वर्ग लोड करने के लिएthis.classfile
बाइट सरणी। परिणामीClass
ऑब्जेक्ट फिर लौटाया जाता है। - यदि नाम मेल नहीं खाता, तो हम
ClassNotFoundException
फेंकClassNotFoundException
।
एक बाहरी .class फ़ाइल लोड हो रही है
एक कक्षा को लोड करने के लिए हमें पहले इसे परिभाषित करने की आवश्यकता है। क्लास को ClassLoader
द्वारा परिभाषित किया गया है। बस एक समस्या है, Oracle ने इस सुविधा के साथ ClassLoader
का कोड नहीं लिखा है। वर्ग को परिभाषित करने के लिए हम नाम के एक विधि का उपयोग करने की आवश्यकता होगी defineClass()
जिनमें से एक निजी तरीका है ClassLoader
।
इसे एक्सेस करने के लिए, हम क्या करेंगे, एक नया वर्ग, ByteClassLoader
, और इसे ClassLoader
तक विस्तारित करेंगे। अब जब हमने अपनी कक्षा को ClassLoader
तक बढ़ा दिया है, तो हम ClassLoader
के निजी तरीकों का उपयोग कर सकते हैं। defineClass()
उपलब्ध करने के लिए, हम एक नई विधि defineClass()
जो निजी defineClass()
विधि के लिए दर्पण की तरह काम करेगी। निजी पद्धति को कॉल करने के लिए हमें क्लास के नाम, name
, क्लास बाइट्स, classBytes
, पहली बाइट्स ऑफ़सेट की आवश्यकता होगी, जो 0
होगा क्योंकि classBytes
का डेटा classBytes[0]
से शुरू होता है, और अंतिम classBytes.lenght
, जो classBytes.lenght
होगा classBytes.lenght
क्योंकि यह डेटा के आकार का प्रतिनिधित्व करता है, जो अंतिम ऑफसेट होगा।
public class ByteClassLoader extends ClassLoader {
public Class<?> defineClass(String name, byte[] classBytes) {
return defineClass(name, classBytes, 0, classBytes.length);
}
}
अब, हमारे पास एक सार्वजनिक defineClass()
विधि है। इसे वर्ग और वर्ग बाइट्स के नाम को तर्क के रूप में पारित करके कहा जा सकता है।
चलो कहते हैं कि हम कक्षा नामित है MyClass
पैकेज में stackoverflow
...
विधि को कॉल करने के लिए हमें क्लास बाइट्स की आवश्यकता होती है इसलिए हम Paths.get()
पद्धति का उपयोग करके और तर्क के रूप में बाइनरी क्लास के पथ को पार करके अपने वर्ग के पथ का प्रतिनिधित्व करते हुए एक Path
ऑब्जेक्ट बनाते हैं। अब, हम Files.readAllBytes(path)
साथ क्लास बाइट्स प्राप्त कर सकते हैं। तो हम एक ByteClassLoader
उदाहरण बनाते हैं और हमारे द्वारा बनाई गई विधि का उपयोग करते हैं, defineClass()
। हमारे पास पहले से ही क्लास बाइट्स हैं, लेकिन अपनी पद्धति को कॉल करने के लिए हमें उस क्लास के नाम की भी आवश्यकता है जो पैकेज नाम (डॉट) क्लास कैनोनिकल नाम है, इस मामले में stackoverflow.MyClass
।
Path path = Paths.get("MyClass.class");
ByteClassLoader loader = new ByteClassLoader();
loader.defineClass("stackoverflow.MyClass", Files.readAllBytes(path);
नोट : defineClass()
विधि एक Class<?>
वस्तु लौटाती है। आप चाहें तो इसे बचा सकते हैं।
कक्षा को लोड करने के लिए, हम बस loadClass()
कॉल loadClass()
और कक्षा का नाम पास करते हैं। यह विधि एक ClassNotFoundException
को फेंक ClassNotFoundException
इसलिए हमें एक कोशिश कैथ ब्लॉक का उपयोग करने की आवश्यकता है
try{
loader.loadClass("stackoverflow.MyClass");
} catch(ClassNotFoundException e){
e.printStackTrace();
}