2010-09-01 13 views
13

मैं वसंत के घोषणात्मक लेनदेन (@ traansactional एनोटेशन) का उपयोग "पहलू" मोड में कर रहा हूं। यह ज्यादातर मामलों में काम करता है जैसा कि इसे करना चाहिए, लेकिन एक के लिए यह नहीं है। हम इसे Lang पर कॉल कर सकते हैं (क्योंकि यही वह है जिसे वास्तव में कहा जाता है)।AspectJ लोड टाइम वीवर सभी वर्गों का पता नहीं लगाता

मैं लोड टाइम वीवर को समस्या को इंगित करने में सक्षम हूं। Aop.xml में डीबग और वर्बोज़ लॉगिंग चालू करके, यह बुने जाने वाले सभी वर्गों को सूचीबद्ध करता है। समस्याग्रस्त वर्ग Lang वास्तव में लॉग में बिल्कुल उल्लेख नहीं किया गया है।

फिर मैंने Lang के शीर्ष पर ब्रेकपॉइंट लगाया, जिससे Lang कक्षा लोड होने पर एक्लिप्स को थ्रेड को निलंबित कर दिया गया। एलटीडब्लू अन्य कक्षाओं को बुनाई करते समय यह ब्रेकपॉइंट मारा जाता है! तो मुझे लगता है कि यह या तो Lang बुनाई करने की कोशिश करता है और विफल रहता है और आउटपुट नहीं करता है, या किसी अन्य वर्ग के पास एक संदर्भ है जो इसे Lang लोड करने के लिए मजबूर करता है इससे पहले कि इसे वास्तव में बुनाई का मौका मिलता है।

मुझे यकीन नहीं है कि इसे कैसे डिबग करना जारी रखें, क्योंकि मैं इसे छोटे पैमाने पर पुन: पेश नहीं कर पा रहा हूं। कैसे चलना है इस पर कोई सुझाव?


अद्यतन: अन्य सुराग भी स्वागत है। उदाहरण के लिए, एलटीडब्ल्यू वास्तव में कैसे काम करता है? ऐसा लगता है कि बहुत सारे जादू हो रहे हैं। क्या एलटीडब्ल्यू से और भी डीबग आउटपुट प्राप्त करने के लिए कोई विकल्प हैं? मैं वर्तमान में है: LTW, जैसे कि, InstrumentationLoadTimeWeaver अनुमति देने के लिए किया जा रहा है वसंत-एजेंट:

<weaver options="-XnoInline -Xreweavable -verbose -debug -showWeaveInfo"> 

मैं भूल गया था टॉम से पहले ही उल्लेख है।


एंडी क्लेमेंट के सुझावों को मैं निरीक्षण करने के लिए है कि क्या AspectJ ट्रांसफार्मर कभी है फैसला किया के आधार पर भी वर्ग पारित कर दिया। मैंने ClassPreProcessorAgent.transform(..) में ब्रेकपॉइंट लगाया, और ऐसा लगता है कि Lang क्लास उस वर्ग तक कभी भी पहुंच नहीं पाती है, भले ही इसे उसी वर्ग लोडर द्वारा अन्य वर्गों (जेटी के WebAppClassLoader का एक उदाहरण) के रूप में लोड किया जा रहा हो।

फिर मैंने InstrumentationLoadTimeWeaver$FilteringClassFileTransformer.transform(..) में ब्रेकपॉइंट डालने के लिए आगे बढ़े। Lang के लिए भी कोई हिट नहीं है। और मेरा मानना ​​है कि सभी लोड किए गए वर्गों के लिए विधि को लागू किया जाना चाहिए, भले ही वे किस श्रेणी लोडर का उपयोग कर रहे हों। यह इस तरह दिखने लग रहा है:

  1. मेरे डिबगिंग के साथ एक समस्या। संभावित रूप से Lang उस समय लोड नहीं होता है जब ग्रहण रिपोर्ट करता है
  2. जावा बग? दूर-दराज, लेकिन मुझे लगता है कि ऐसा होता है।

अगला सुराग: मैं -verbose:class चालू है और यह रूप में अगर Lang है समय से पहले ही लोड किए जा रहे प्रतीत होता है - शायद पहले ट्रांसफार्मर इंस्ट्रुमेंटेशन में जोड़ा जाता है। विचित्र रूप से, मेरे ग्रहण ब्रेकपॉइंट इस लोडिंग को पकड़ नहीं लेता है।

इसका मतलब है कि वसंत नया संदिग्ध है। ConfigurationClassPostProcessor में कुछ प्रसंस्करण प्रतीत होता है जो कक्षाओं को उनका निरीक्षण करने के लिए लोड करता है। यह मेरी समस्या से संबंधित हो सकता है।


ConfigurationClassBeanDefinitionReader में ये लाइनें का कारण बनता है Lang वर्ग पढ़ने के लिए:

else if (metadata.isAnnotated(Component.class.getName()) || 
     metadata.hasAnnotatedMethods(Bean.class.getName())) { 
    beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE); 
    return true; 
} 
वर्ग है, जो कि कक्षा में सभी तरीकों के सभी पैरामीटर वर्गों को लोड करता है पर

विशेष रूप से, metadata.hasAnnotatedMethods() कॉल getDeclaredMethods()। मुझे लगता है कि यह समस्या का अंत नहीं हो सकता है, क्योंकि मुझे लगता है कि कक्षाओं को उतार दिया जाना चाहिए। क्या अज्ञात कारणों के लिए जेवीएम कक्षा के उदाहरण को कैश कर सकता है?

उत्तर

7

ठीक है, मैं समस्या को हल कर दिया है। अनिवार्य रूप से, यह कुछ कस्टम एक्सटेंशन के साथ एक वसंत समस्या है। अगर कोई ऐसा कुछ मिलता है, तो मैं क्या हो रहा है, चरणबद्ध तरीके से व्याख्या करने की कोशिश करूंगा।

सबसे पहले, हमारे पास हमारे प्रोजेक्ट में कस्टम BeanDefintionParser है। ।

private static class ControllerBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { 

    protected Class<?> getBeanClass(Element element) { 
     try { 
      return Class.forName(element.getAttribute("class")); 
     } catch (ClassNotFoundException e) { 
      throw new RuntimeException("Class " + element.getAttribute("class") + "not found.", e); 
     } 
    } 

// code to parse XML omitted for brevity 

} 

अब, समस्या के बाद सभी सेम परिभाषा पढ़ा गया है और BeanDefinitionRegistryPostProcessor में किक करने इस स्तर पर शुरू होता है, कहा जाता है एक वर्ग ConfigurationClassPostProcessor सभी सेम परिभाषाओं के माध्यम से देख शुरू होता है होता है, खोज करने के लिए: इस वर्ग निम्नलिखित परिभाषा था @Configuration के साथ एनानेटेड बीन कक्षाओं के लिए या जिनके पास @Bean के साथ विधियां हैं।

एक बीन के लिए एनोटेशन पढ़ने की प्रक्रिया में, यह AnnotationMetadata इंटरफ़ेस का उपयोग करता है। अधिकांश नियमित बीन्स के लिए, AnnotationMetadataVisitor नामक उप-वर्ग का उपयोग किया जाता है। हालांकि, बीन परिभाषाओं को पार्स करते समय, यदि आपने कक्षा उदाहरण को वापस करने के लिए getBeanClass() विधि को ओवरराइड किया है, जैसा कि हमारे पास था, तो StandardAnnotationMetadata उदाहरण का उपयोग किया जाता है। जब StandardAnnotationMetadata.hasAnnotatedMethods(..) लागू किया जाता है, तो यह Class.getDeclaredMethods() पर कॉल करता है, जो बदले में कक्षा लोडर को उस वर्ग में पैरामीटर के रूप में उपयोग की जाने वाली सभी कक्षाओं को लोड करने का कारण बनता है। इस तरह से लोड की गई कक्षाएं सही तरीके से अनलोड नहीं होती हैं, और इस प्रकार कभी भी बुनाई नहीं होती है, क्योंकि यह AspectJ ट्रांसफॉर्मर पंजीकृत होने से पहले होता है।

अब, मेरी समस्या मैं बहुत की तरह एक वर्ग था कि था:

public class Something { 
    private Lang lang; 
    public void setLang(Lang lang) { 
     this.lang = lang; 
    } 
} 

फिर, मैं कक्षा Something कि हमारे कस्टम ControllerBeanDefinitionParser का उपयोग कर पार्स किया गया था की एक सेम था। इसने गलत एनोटेशन डिटेक्शन प्रक्रिया शुरू की, जिसने अप्रत्याशित वर्ग लोडिंग को ट्रिगर किया, जिसका मतलब था कि AspectJ को Lang बुनाई का मौका कभी नहीं मिला। दिन की

private static class ControllerBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { 

    protected String getBeanClassName(Element element) { 
     return element.getAttribute("class"); 
    } 

// code to parse XML omitted for brevity 

} 

सबक: getBeanClass ओवरराइड न करें जब तक आप वास्तव में यह मतलब

समाधान getBeanClass(..) पर हावी नहीं करने के लिए, लेकिन इसके बजाय getBeanClassName(..) ओवरराइड, जो दस्तावेज़ के अनुसार बेहतर है था। असल में, अपने स्वयं के बीनडिफिनिशन पार्सर को लिखने की कोशिश न करें जबतक कि आप नहीं जानते कि आप क्या कर रहे हैं।

फिन।

1

विकल्प 1) पहलू जे खुला स्रोत है। इसे खोलें और देखें कि क्या हो रहा है।

विकल्प 2) बैंग के लिए अपने वर्ग का नाम बदलें, देखें कि क्या यह काम कर रहा

मैं नहीं है, हालांकि मैं क्यों नहीं कह सकता है, अगर वहाँ मुश्किल कोडिंग वहाँ में " 'को छोड़ लैंग है आश्चर्य होगा शुरू होता है।

संपादित करें -

स्रोत

 if (superclassnameIndex > 0) { // May be zero -> class is java.lang.Object 
      superclassname = cpool.getConstantString(superclassnameIndex, Constants.CONSTANT_Class); 
      superclassname = Utility.compactClassName(superclassname, false); 

} else { 
      superclassname = "java.lang.Object"; 
     } 

ऐसा लगता है कि वे java.lang.stuff की बुनाई छोड़ कोशिश कर रहे हैं में इस तरह कोड देखकर .... बस "लैंग" के लिए कुछ भी नहीं दिख रहा है लेकिन यह वहां हो सकता है (या एक बग)

+0

उत्तर के लिए धन्यवाद। दिलचस्प विचार है कि स्ट्रिंग "लैंग" एक समस्या का कारण बन सकती है। लेकिन मुझे उल्लेख करना चाहिए था, अन्य वर्ग भी हैं (कम से कम एक) भी बुना नहीं जा रहा है। अन्य ज्ञात व्यक्ति को कमसेवर कहा जाता है। तो मुझे शक है कि समस्या है। हालांकि मुझे एस्पेक्टजे स्रोत को देखना शुरू करना पड़ सकता है। – waxwing

4

यदि आपकी कक्षा का उल्लेख -verbose/-debug आउटपुट में नहीं किया गया है, जो मुझे बताता है कि लोडर द्वारा लोड नहीं किया जा रहा है, तो आपको लगता है कि यह है। क्या आप 100% सुनिश्चित कर सकते हैं कि 'लैंग' पदानुक्रम में उच्च श्रेणी के क्लासपास्टर के वर्गपंथ पर नहीं है? जब आप अपना ब्रेकपॉइंट ट्रिगर करते हैं तो उस क्लासलोडर उस बिंदु पर लैंग लोड कर रहा है?

इसके अलावा, आप AspectJ संस्करण का उल्लेख नहीं करते हैं - यदि आप 1.6.7 पर हैं, तो किसी भी चीज के लिए ltw के साथ समस्याएं थीं लेकिन एक छोटा aop.xml। आपको 1.6.8 या 1.6.9 पर होना चाहिए।

वास्तव में ltw कैसे काम करता है?

बस रखें, प्रत्येक क्लासलोडर के लिए एक AspectJ वीवर बनाया गया है जो कोड बुनाई कर सकता है। AspectJ से पूछा जाता है कि क्या यह वीएम को परिभाषित करने से पहले कक्षा के लिए बाइट्स को संशोधित करना चाहता है। AspectJ किसी भी aop.xml फ़ाइलों को देखता है, यह क्लासलोडर के माध्यम से 'संसाधन' (संसाधनों के रूप में) देख सकता है और स्वयं को कॉन्फ़िगर करने के लिए उनका उपयोग करता है। एक बार कॉन्फ़िगर किए जाने पर यह पहलुओं को निर्दिष्ट करता है, ध्यान में रखते हुए सभी को क्लॉज शामिल/बहिष्कृत करते हैं।

एंडी क्लेमेंट
AspectJ परियोजना का नेतृत्व

+0

मेरे पास मेरी युद्ध libs में facjweaver और aspectjrt का 1.6.9 है। Lang.class.getClassLoader() वही क्लासलोडर उदाहरण देता है जो बुना हुआ एक और वर्ग है। इसके बाद मैंने ClassPreProcessorAgent में ब्रेकपॉइंट डालने का प्रयोग किया, और वास्तव में, लैंग कभी भी इसके ट्रांसफॉर्म() विधि को पारित नहीं किया जाता है। शायद मुझे इसे टॉमकैट पर तैनात करने की कोशिश करनी चाहिए। – waxwing

+0

जब आपने 'बहुत जल्दी' लोड होने के बारे में समस्या का उल्लेख किया, तो उसने मुझे याद दिलाया कि मैंने इसे वसंत के साथ पहले देखा है। वसंत जिरा की एक त्वरित खोज ने https://jira.springframework.org/browse/SPR-4963 लाया जो एक समान प्रकार की समस्या है। यह क्लास रीट्रान्सफॉर्मेशन को एक उत्तर के रूप में सुझाता है (जहां क्लास को मूल बाइट्स का उपयोग करके लोडिंग प्रक्रिया के माध्यम से फिर से चलाया जाएगा, लेकिन दूसरी बार AspectJ के माध्यम से इसे देखेगा), लेकिन जहां तक ​​मुझे पता है कि हमने कुछ भी नहीं किया है इसके लिए वसंत में अभी तक - मुझे नहीं लगता कि 3.1 के लिए कुछ भी योजना बनाई गई है। –

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