मुझे एक बड़ा वर्ग जावा के साथ एक बड़ा java ee अनुप्रयोग मिला है, जो बहुत सारे xml प्रसंस्करण करता है। वर्तमान में मैं अपने कुछ कार्यों को गति देने और नमूना प्रोफाइलरों के माध्यम से धीमा कोड पथों का पता लगाने की कोशिश कर रहा हूं।
एक बात जिस पर मैंने गौर किया, वह यह कि हमारे कोड के कुछ हिस्सों में, जैसे कि हमारे पास कॉल आते TransformerFactory.newInstance(...)
हैं, बेहद सुस्त हैं। मैंने इस FactoryFinder
पद्धति को findServiceProvider
हमेशा एक नया ServiceLoader
उदाहरण बनाने के लिए ट्रैक किया । में ServiceLoader
जावाडोक मैं कैशिंग के बारे में निम्न नोट मिला:
प्रदाता स्थित हैं और तात्कालिक रूप से आलसी हैं, अर्थात मांग पर। सर्विस लोडर उन प्रदाताओं का कैश रखता है जो अब तक लोड किए गए हैं। इट्रेटर विधि का प्रत्येक आह्वान एक इटैटर देता है जो पहले कैश के सभी तत्वों को तुरंत क्रम में प्राप्त करता है, और फिर किसी भी शेष प्रदाताओं को आलसी रूप से पता लगाता है और चालू करता है, प्रत्येक को बदले में कैश में जोड़ता है। पुनः लोड विधि के माध्यम से कैश को साफ किया जा सकता है।
अब तक सब ठीक है। यह OpenJDKs FactoryFinder#findServiceProvider
विधि का एक हिस्सा है :
private static <T> T findServiceProvider(final Class<T> type)
throws TransformerFactoryConfigurationError
{
try {
return AccessController.doPrivileged(new PrivilegedAction<T>() {
public T run() {
final ServiceLoader<T> serviceLoader = ServiceLoader.load(type);
final Iterator<T> iterator = serviceLoader.iterator();
if (iterator.hasNext()) {
return iterator.next();
} else {
return null;
}
}
});
} catch(ServiceConfigurationError e) {
...
}
}
हर पुकार पर findServiceProvider
पुकार ServiceLoader.load
। यह हर बार एक नया ServiceLoader बनाता है । इस तरह से ऐसा लगता है कि सर्विसवैलर्स कैशिंग तंत्र का कोई उपयोग नहीं है। प्रत्येक कॉल अनुरोधित ServiceProvider के लिए classpath को स्कैन करता है।
मैंने पहले से ही क्या प्रयास किया है:
- मुझे पता है कि आप
javax.xml.transform.TransformerFactory
एक विशिष्ट कार्यान्वयन निर्दिष्ट करने के लिए सिस्टम गुण सेट कर सकते हैं । इस तरह से FactoryFinder ServiceLoader प्रक्रिया और उसके सुपर फास्ट का उपयोग नहीं करता है। अफसोस की बात है कि यह एक jvm विस्तृत संपत्ति है और मेरे jvm में चल रही अन्य जावा प्रक्रियाओं को प्रभावित करती है। उदाहरण के लिए सैक्सन के साथ मेरे एप्लिकेशन शिप औरcom.saxonica.config.EnterpriseTransformerFactory
मुझे एक और एप्लिकेशन मिला है, जो सैक्सन के साथ शिप नहीं करता है। जैसे ही मैं सिस्टम प्रॉपर्टी सेट करता हूं, मेरा अन्य एप्लिकेशन शुरू होने में विफल रहता है, क्योंकिcom.saxonica.config.EnterpriseTransformerFactory
इसके क्लासपाथ पर कोई भी नहीं है । इसलिए यह मेरे लिए कोई विकल्प नहीं लगता है। - मैंने पहले से ही हर उस जगह को रिफैक्ट कर दिया है जहां a
TransformerFactory.newInstance
को कॉल किया जाता है और TransformerFactory को कैश करता है। लेकिन मेरी निर्भरता में विभिन्न स्थान हैं जहां मैं कोड को रिफलेक्टर नहीं कर सकता।
मेरा सवाल है: क्यों FactoryFinder एक ServiceLoader का पुन: उपयोग नहीं करता है? क्या सिस्टम के गुणों का उपयोग करने के अलावा इस पूरी ServiceLoader प्रक्रिया को तेज करने का कोई तरीका है? क्या इसे JDK में नहीं बदला जा सकता है ताकि किसी FactoryFinder ने ServiceLoader उदाहरण का पुन: उपयोग किया हो? इसके अलावा यह किसी एकल FactoryFinder के लिए विशिष्ट नहीं है। यह bahaviour javax.xml
पैकेज में सभी FactoryFinder वर्गों के लिए समान है जिसे मैंने अब तक देखा है।
मैं OpenJDK 8/11 का उपयोग कर रहा हूं। मेरे आवेदन एक Tomcat 9 उदाहरण में तैनात हैं।
संपादित करें: अधिक विवरण प्रदान करना
यहाँ एक एकल XMLInputFactory.newInstance कॉल के लिए कॉल स्टैक दिया गया है:
जहां ज्यादातर संसाधनों का उपयोग किया जाता है ServiceLoaders$LazyIterator.hasNextService
। यह विधि फ़ाइल getResources
को पढ़ने के लिए ClassLoader पर कॉल करती META-INF/services/javax.xml.stream.XMLInputFactory
है। हर बार अकेले कॉल करने में लगभग 35ms लगते हैं।
क्या इन फ़ाइलों को बेहतर कैश करने के लिए टॉमकैट को निर्देश देने का एक तरीका है ताकि उन्हें तेजी से सेवा दी जाए?
-D
अपनी Tomcat
प्रक्रिया में ध्वज का उपयोग करके संपत्ति सेट करने का प्रयास किया है? उदाहरण के लिए: -Djavax.xml.transform.TransformerFactory=<factory class>.
इसे अन्य ऐप्स के लिए संपत्तियों को ओवरराइड नहीं करना चाहिए। आपकी पोस्ट अच्छी तरह से वर्णित है और शायद आपने इसे आज़माया है, लेकिन मैं पुष्टि करना चाहता हूं। Javax.xml.transform.TransformerFactory सिस्टम प्रॉपर्टी को सेट करने का तरीका देखें , Tomcat में HeapMemory या JVM Arguments कैसे सेट करें