2014-11-30 7 views
9

मेरे पास दो वर्ग (A और B) हैं जो विभिन्न ClassLoaders द्वारा लोड किए गए हैं। इसके अलावा, मेरे पास एक तीसरी कक्षा है, जो स्थिर गेटर और सेटर विधियों को प्रदान करती है। मैं चित्र निम्नलिखित उम्मीद स्थिति स्पष्ट कर सकते हैं:विभिन्न क्लासलोडर्स द्वारा लोड की गई कक्षाओं से स्थिर स्थिर विधि

enter image description here

Data वर्ग निम्नलिखित के रूप में दिखता है:

public class Data { 

    private static String data = "<fill in>"; 

    public static void setData(String d) { 
     data = d; 
    } 

    public static String getData() { 
     return data; 
    } 
} 

वर्ग A में, मैं Data के स्थिर मूल्य निर्धारित करना चाहते हैं और B में मैं चाहता हूँ इस मूल्य को पुनः प्राप्त करने के लिए। हालांकि, B में मुझे हमेशा मूल मान मिलता है (जो "<fill in>" है)। मुझे केवल ClassLoader एस की बुनियादी समझ है, इसलिए मुझे यकीन नहीं है कि हुड के नीचे क्या चल रहा है। मैंने सोचा कि क्लासलोडर्स (clA और clB) दोनों अपने माता-पिता ClassLoader पर प्रचार करेंगे और मुझे दोनों में Data कक्षा मिल जाएगी। क्या कोई मुझे व्यवहार पर कुछ प्रतिक्रिया दे सकता है या मुझे देखने के लिए दिशा में इंगित कर सकता है?

अद्यतन

जब मैं दोनों Data वर्गों के hashCode() प्रिंट, मैं उन्हें अलग-अलग मान मिलता है (जाहिर है, जिसका अर्थ है मैं एक ही कक्षा का उपयोग नहीं मिलता है)। क्या ClassLoader पदानुक्रम को चित्रित करने का कोई आसान तरीका है?

+3

क्या आप सुनिश्चित हैं कि 'कक्षा ए' और 'कक्षा बी' दोनों से बात कर रहे हैं एक ही क्लासलोडर द्वारा लोड की गई 'डेटा' कक्षा में "समान" 'डेटा' वर्ग? यदि विभिन्न क्लासलोडर्स द्वारा 'डेटा' लोड किया जा रहा है और' कक्षा ए 'और' कक्षा बी 'ऐसे विभिन्न संस्करणों से बात कर रहे हैं, तो आप जो देख रहे हैं, वह अपेक्षित है। यह क्लासलोडर पदानुक्रम पर बहुत निर्भर करता है, इसलिए उस संदर्भ का थोड़ा सा मदद करेगा। – mystarrocks

+0

@mystarrocks प्रतिक्रिया के लिए धन्यवाद, जो पहले से ही मदद की है। ऐसा लगता है कि मुझे वास्तव में एक ही कक्षा संदर्भ नहीं मिलता है। मैंने तदनुसार अपना प्रश्न अपडेट किया। धन्यवाद! – WeSt

+0

क्या ये कक्षाएं किसी ऐसे अनुप्रयोग से संबंधित हैं जो सर्वर पर चल रही है? विभिन्न कंटेनर विभिन्न वर्गीकरण तकनीकों का उपयोग करते हैं। – mystarrocks

उत्तर

2

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

def showObjectClassLoaderHierarchy(Object obj) { 
    def classLoader = showClassLoaderHierarchy(obj.getClass().getClassLoader()); 
    showClassLoaderHierarchy(classLoader); 
} 

def showClassLoaderHierarchy(ClassLoader loader) { 

    if (loader != null) { 
     println "Classloader: " + loader.hashCode(); 
     while (loader.getParent() != null) { 
       loader = loader.getParent(); 
      println " Child of: " + loader.hashCode(); 
     } 
    } 

} 

मैं तुम्हें मिलेगा लगता है, अपने कोड में, दो डाटा वस्तुओं वास्तव में एक ही classloader, जिसके कारण वे से लोड नहीं कर रहे हैं विभिन्न स्थिर चर।

मैं एक साथ एक नमूना है कि है

  • मुख्य डाल एक स्थिर स्ट्रिंग (माता-पिता classloader से भी भरा हुआ है)
  • LoadA, जो DataObj की एक प्रति को दर्शाता है के साथ (मूल classloader से लोड)
  • DataObj (बच्चे classloader एक से लोड)
  • LoadB, जो DataObj की एक प्रति को दर्शाता है (बच्चे classloader बी से भरी हुई)

मुझे लगता है कि लोडए और लोडबी के पास अलग-अलग क्लासलोडर हैं, जबकि डेटाओबीजे और स्थिर चर एक सामान्य क्लासलोडर से आते हैं।

पूर्ण कोड पर: https://github.com/lucasmcgregor/groovy_classloader_test

ग्रूवी में मुख्य वस्तु:

import java.lang.ClassLoader; 
import java.net.URLClassLoader; 
import java.net.URL; 

def showObjectClassLoaderHierarchy(Object obj) { 
     def classLoader = showClassLoaderHierarchy(obj.getClass().getClassLoader()); 
     showClassLoaderHierarchy(classLoader); 
} 

def showClassLoaderHierarchy(ClassLoader loader) { 

     if (loader != null) { 
      println "Classloader: " + loader.hashCode(); 
      while (loader.getParent() != null) { 
        loader = loader.getParent(); 
        println " Child of: " + loader.hashCode(); 
      } 
     } 

} 

println "Setting up child classLoaders A and B..."; 

def URL[] urlsA = [new URL("file:///tmp/cla/")]; 
def classLoaderA = new URLClassLoader(urlsA, this.getClass().getClassLoader()); 

def URL[] urlsB = [new URL("file:///tmp/clb/")]; 
def classLoaderB = new URLClassLoader(urlsB, this.getClass().getClassLoader()); 


println "Classloader A heirachry:"; 
showClassLoaderHierarchy(classLoaderA); 

println "Classloader B: "; 
showClassLoaderHierarchy(classLoaderB); 

println ""; 
println "Now loading Load classes A and B from seperate classloaders:"; 
def loadA = classLoaderA.loadClass("LoadA").newInstance(); 
def loadB = classLoaderB.loadClass("LoadB").newInstance(); 

print "LoadA: heirachry"; 
showObjectClassLoaderHierarchy(loadA); 
print "LoadB: heirachry"; 
showObjectClassLoaderHierarchy(loadB); 

println ""; 
println "Now pulling the data objects from both and comparing classloders and static data: "; 
def dobjA = loadA.getDataObj(); 
def dobjB = loadB.getDataObj(); 

println "dataA static field:" + dobjA.getData(); 
println "dataA static field hashcode: " + dobjA.getData().hashCode(); 
println "dataA hashcode: " + dobjA.hashCode(); 
println "dataA classloader: "; 
showObjectClassLoaderHierarchy(dobjA); 

println "dataB static field: " + dobjB.getData(); 
println "dataB static field hashcode: " + dobjB.getData().hashCode(); 
println "dataB hashcode: " + dobjB.hashCode(); 
println "dataB classLoader:"; 
showObjectClassLoaderHierarchy(dobjB); 

परिणाम हैं:

Setting up child classLoaders A and B... 
Classloader A heirachry: 
Classloader: 1926764753 
    Child of: 1163157884 
    Child of: 1022308509 
Classloader B: 
Classloader: 846238611 
    Child of: 1163157884 
    Child of: 1022308509 

Now loading Load classes A and B from seperate classloaders: 
LoadA: heirachryClassloader: 1926764753 
    Child of: 1163157884 
    Child of: 1022308509 
LoadB: heirachryClassloader: 846238611 
    Child of: 1163157884 
    Child of: 1022308509 

Now pulling the data objects from both and comparing classloders and static data: 
dataA static field:Loaded By B 
dataA static field hashcode: 1828548084 
dataA hashcode: 2083117811 
dataA classloader: 
Classloader: 1163157884 
    Child of: 1022308509 
dataB static field: Loaded By B 
dataB static field hashcode: 1828548084 
dataB hashcode: 157683534 
dataB classLoader: 
Classloader: 1163157884 
    Child of: 1022308509 

आप देखते हैं कि LoadA और LoadB दोनों अलग classloaders है, लेकिन वे एक पैरेंट क्लासलोडर साझा करें।

पैरेंट क्लासलोडर LoadA.dataObj और LoadB.dataObj दोनों उदाहरणों के लिए DataObj लोड करता है।

LoadA.dataObj और LoadB.dataObj के पास विभिन्न हैशकोड हैं।

हालांकि, LoadA.dataObj.data और LoadB.dataObj.data में एक ही हैशकोड है, क्योंकि यह स्थिर वस्तु है। उनके पास एक ही मूल्य है। लोडब ने अपना डेटा ओबीजी को अंतिम रूप दिया और स्ट्रिंग को "बी द्वारा लोड किया गया"

1

मुझे लगता है कि लुकास ने पदानुक्रम को चित्रित करने के लिए वास्तव में आपके प्रश्न का उत्तर दिया। मैं प्रश्न का कुछ अनुस्मारक साफ़ करने के लिए केवल अपना उत्तर जोड़ना चाहता हूं

जावा में जोड़ी (क्लासलोडर परिभाषित करना, वर्ग का नाम) अद्वितीय है। यहां क्लासलोडर को परिभाषित करना मतलब है लोडर, जो वास्तव में क्लास को बाइटकोड से कक्षा के रूप में महसूस करता है। इस विशिष्टता का मतलब है कि कक्षा X को परिभाषित करने वाला क्लासलोडर द्वितीय श्रेणी एक्स को परिभाषित नहीं कर सकता है, इसका एक अलग नाम होना चाहिए। लेकिन एक और क्लासलोडर कक्षा को परिभाषित कर सकता है। क्लासलोडर एक प्रकार के पेड़ में संरचित होते हैं (यह वास्तव में एक डीएजी नहीं है, लेकिन यह यहां तक ​​कि यहां तक ​​जाता है) और क्लासलोडर को कक्षा के लिए पूछे जाने पर पहले अपने माता-पिता से पूछना चाहिए। तो ऐसा हो सकता है कि डेटा दो बार मौजूद है, उदाहरण के लिए सीआईए में और एक बार सीआईबी में। इससे बचने के लिए आप आमतौर पर क्लासलोडर द्वारा डेटा परिभाषित करना चाहते हैं जो सीआईए और सीआईबी के माता-पिता हैं। यह माना जाता है कि दो लोडर क्लासलोडर बाधाओं के अनुसार व्यवहार करते हैं, जैसे माता-पिता से पहले पूछना।

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

एक चेतावनी ... GroovyClassLoader पूरी तरह से व्यवहार करने वाला वर्ग लोडर नहीं है। यह माता-पिता से कक्षाओं पर परिभाषित कक्षाओं (उदाहरण के लिए एक स्क्रिप्ट के माध्यम से) prefere होगा। यदि आपके पास कक्षा डेटा के साथ एक स्क्रिप्ट है, तो वह उस डेटा क्लास का उपयोग करेगा, भले ही माता-पिता सामान्य रूप से परिभाषित क्लासलोडर

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