JDK डायनेमिक प्रॉक्सी और CGLib में क्या अंतर है?


147

प्रॉक्सी डिज़ाइन पैटर्न के मामले में , JDK के डायनेमिक प्रॉक्सी और थर्ड पार्टी डायनामिक कोड जेनरेशन API जैसे कि CGLib में क्या अंतर है ?

दोनों दृष्टिकोणों का उपयोग करने के बीच अंतर क्या है और कब एक को दूसरे पर पसंद करना चाहिए?


3
यहां कोड प्राप्त करें: < gist.github.com/ksauzz/1563486 > Cglib में आप वर्ग प्रॉक्सी और इंटरफ़ेस प्रॉक्सी दोनों बना सकते हैं। स्प्रिंग डिफ़ॉल्ट रूप से CGlib का उपयोग करता है जबकि AspectJ जावा प्रॉक्सी का उपयोग करता है। इसे भी पढ़ें: jnb.ociweb.com/jnb/jnbNov2005.html ;)
रे

जवाबों:


185

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

CGLIB (और javassist) सबक्लासिंग द्वारा एक प्रॉक्सी बना सकते हैं। इस परिदृश्य में प्रॉक्सी लक्ष्य वर्ग का एक उपवर्ग बन जाता है। इंटरफेस की जरूरत नहीं।

तो जावा डायनामिक प्रॉक्सी प्रॉक्सी कर सकती है: public class Foo implements iFooजहाँ CGLIB प्रॉक्सी कर सकती है:public class Foo

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

मुझे यह उल्लेख करना चाहिए कि क्योंकि javassist और CGLIB उपवर्ग का उपयोग करके प्रॉक्सी का उपयोग करते हैं, यही कारण है कि आप इस पर भरोसा करने वाले चौखटे का उपयोग करते समय अंतिम विधियों की घोषणा नहीं कर सकते हैं या वर्ग को अंतिम नहीं बना सकते हैं। यह इन पुस्तकालयों को आपकी कक्षा को उप-वर्ग करने और आपके तरीकों को ओवरराइड करने की अनुमति देने से रोक देगा।


धन्यवाद..!! लेकिन यह उपयोगी होगा यदि आप मुझे किसी मामले में किसी दूसरे के उपयोग को स्पष्ट करने के लिए एक उदाहरण कोड (या लिंक) दे सकते हैं .. !!!
केडजाव

1
ध्यान दें कि JDK परदे के पीछे वास्तव में IFoo के लिए प्रॉक्सी का हवाला देते हुए किसी भी तरह के फू के लिए बिल्कुल भी नहीं है। यह एक महत्वपूर्ण भेद है। इसके अलावा, cglib proxies पूर्ण उपवर्ग हैं - इसका लाभ उठाएं! केवल उन्हीं प्रॉक्सी तरीकों के लिए फ़िल्टर का उपयोग करें जिनकी आप परवाह करते हैं और सीधे उत्पन्न वर्ग का उपयोग करते हैं।
lscoughlin

9
यह भी ध्यान दिया जाना चाहिए कि CGLib उप-वर्ग निर्माण के लिए सुपर क्लास के बारे में पर्याप्त जानना आवश्यक है ताकि सही कंस्ट्रक्टर के साथ सही कंस्ट्रक्टर को कॉल करने में सक्षम हो। इंटरफ़ेस आधारित प्रॉक्सी के विपरीत जो निर्माणकर्ताओं की परवाह नहीं करता है। यह JDK परदे के पीछे CGLib प्रॉक्सी के साथ "स्वचालित" कम काम करता है। एक और अंतर "स्टैक" लागत में है। एक JDK प्रॉक्सी हमेशा प्रति कॉल अतिरिक्त स्टैक फ़्रेम लगाता है जबकि CGLib में किसी अतिरिक्त स्टैक फ़्रेम की लागत नहीं हो सकती है। यह तेजी से प्रासंगिक हो जाता है कि ऐप जितना अधिक जटिल हो जाता है (क्योंकि स्टैक जितना बड़ा होता है, मेमोरी मेमोरी अधिक खपत होती है)।
रे

1
cglib नहीं कर सकते हैं प्रॉक्सी अंतिम तरीकों, लेकिन अपवाद नहीं होगा gist.github.com/mhewedy/7345403cfa52e6f47563f8a204ec0e80
मुहम्मद Hewedy

हां, CGLIB केवल अंतिम तरीकों की अनदेखी करता है।
yashjain12yj

56

कार्यक्षमता में अंतर

  • JDK परदे के पीछे रहते हुए इंटरफेस के किसी भी सेट को लागू करने की अनुमति देता है Object। किसी भी इंटरफ़ेस विधि, प्लस Object::hashCode, Object::equalsऔर Object::toStringफिर एक को अग्रेषित किया जाता है InvocationHandler। इसके अतिरिक्त, मानक पुस्तकालय इंटरफ़ेस java.lang.reflect.Proxyलागू किया गया है।

  • cglib आपको किसी भी गैर-अंतिम वर्ग को उप-वर्ग करते हुए इंटरफेस के किसी भी सेट को लागू करने की अनुमति देता है। इसके अलावा, तरीकों को वैकल्पिक रूप से ओवरराइड किया जा सकता है, अर्थात सभी गैर-अमूर्त तरीकों को इंटरसेप्ट करने की आवश्यकता नहीं है। इसके अलावा, एक विधि को लागू करने के विभिन्न तरीके हैं। यह एक InvocationHandlerवर्ग (एक अलग पैकेज में) भी प्रदान करता है , लेकिन यह उदाहरण के लिए अधिक उन्नत इंटरसेप्टर्स का उपयोग करके सुपर तरीकों को कॉल करने की भी अनुमति देता है MethodInterceptor। इसके अलावा, cglib जैसे विशेष अवरोधन द्वारा प्रदर्शन में सुधार कर सकता है FixedValue। मैंने एक बार cglib के लिए विभिन्न इंटरसेप्टर्स का सारांश लिखा था ।

प्रदर्शन के अंतर

JDK प्रॉक्सी, केवल एक अवरोधन डिस्पैचर के साथ नहीं बल्कि भोलेपन से लागू किया जाता है InvocationHandler। इसके लिए कार्यान्वयन के लिए एक आभासी विधि प्रेषण की आवश्यकता होती है जिसे हमेशा इनलेट नहीं किया जा सकता है। Cglib विशेष बाइट कोड बनाने की अनुमति देता है जो कभी-कभी प्रदर्शन में सुधार कर सकता है। यहाँ 18 ठूंठ विधियों के साथ एक इंटरफ़ेस को लागू करने के लिए कुछ तुलनाएं हैं:

            cglib                   JDK proxy
creation    804.000     (1.899)     973.650     (1.624)
invocation    0.002     (0.000)       0.005     (0.000)

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


2
स्प्रिंग डॉक्यूमेंटेशन के बाद JDK को cglib से अधिक पसंद करने के कारण उत्तरार्द्ध के प्रदर्शन का लाभ मिला है? docs.spring.io/spring/docs/2.5.x/reference/…
P4ndaman

2
Cglib एक बाहरी निर्भरता है और वर्तमान में असमर्थित है। थर्ड-पार्टी सॉफ्टवेयर पर भरोसा करना हमेशा एक जुआ है, इसलिए यह सबसे अच्छा है जब कम से कम लोग इस पर भरोसा करते हैं।
राफेल विंटरथेलर

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

यदि आप प्रॉक्सी ऑब्जेक्ट पर एक विधि कहते हैं, तो हमारे आह्वान हैंडलर के माध्यम से किसी भी कॉल को रूट किया जाता है। यदि कोई आह्वान हैंडलर कॉल प्रतिनिधि को ऑब्जेक्ट पर कॉल करता है, तो उल्लेखित पुनरावृत्ति होती है।
राफेल विंटरहेल्टर

हाय राफेल, संदेश आपके उत्तर से असंबंधित है, मैं आपको 5 साल पहले किए गए एक संपादन के बारे में बता रहा हूं । जैसा कि cglib ने स्पष्ट रूप से अभी भी 2019 में कमिट किया है, और इसके रीडमी में कोई भी गिरफ्तार विकास नहीं दिखा रहा है, मैंने आपके कथन को टैग अंश से हटा दिया है । यदि कोई उल्लेख करने के लिए प्रासंगिक है तो टैग विवरण / उद्धरण में सुधार करने के लिए स्वतंत्र महसूस करें।
कूर

28

डायनेमिक प्रॉक्सी: JDK परावर्तन एपीआई का उपयोग करके रनटाइम पर इंटरफेस का गतिशील कार्यान्वयन ।

उदाहरण: वसंत लेनदेन के लिए गतिशील परदे के पीछे का उपयोग करता है:

यहां छवि विवरण दर्ज करें

उत्पन्न प्रॉक्सी बीन के ऊपर आती है। यह बीन में पारम्परिक व्यवहार जोड़ता है। यहाँ प्रॉक्सी JDK परावर्तन एपीआई का उपयोग करके रनटाइम पर गतिशील रूप से उत्पन्न होता है।

जब कोई एप्लिकेशन बंद हो जाता है, तो प्रॉक्सी नष्ट हो जाएगी और हमारे पास फ़ाइल सिस्टम पर केवल इंटरफ़ेस और बीन होगा।


उपरोक्त उदाहरण में हमारे पास इंटरफ़ेस है। लेकिन इंटरफ़ेस के अधिकांश कार्यान्वयन में सबसे अच्छा नहीं है। तो सेम एक इंटरफ़ेस को लागू नहीं करता है, उस स्थिति में हम विरासत का उपयोग करते हैं:

यहां छवि विवरण दर्ज करें

इस तरह के परदे के पीछे उत्पन्न करने के लिए, स्प्रिंग CGLib नामक एक तृतीय पक्ष पुस्तकालय का उपयोग करता है ।

CGLib ( सी स्तोत्र जी eneration लिब rary) के शीर्ष पर बनाया गया है एएसएम , यह मुख्य रूप प्रॉक्सी का विस्तार सेम पैदा करते हैं और प्रॉक्सी तरीकों में सेम व्यवहार कहते हैं प्रयोग किया जाता है।

JDK डायनेमिक प्रॉक्सी और CGLib के उदाहरण

वसंत रेफरी


5

वसंत प्रलेखन से :

स्प्रिंग AOP किसी दिए गए लक्ष्य वस्तु के लिए प्रॉक्सी बनाने के लिए या तो JDK डायनेमिक प्रॉक्सी या CGLIB का उपयोग करता है। (जब भी आपके पास विकल्प हो JDK डायनेमिक प्रॉक्सी पसंद की जाती है)।

यदि लक्ष्य वस्तु को कम से कम एक इंटरफ़ेस पर लागू किया जाना है तो JDK डायनेमिक प्रॉक्सी का उपयोग किया जाएगा। लक्ष्य प्रकार द्वारा लागू किए गए सभी इंटरफेस अनुमानित होंगे। यदि लक्ष्य ऑब्जेक्ट किसी भी इंटरफेस को लागू नहीं करता है तो एक CGLIB प्रॉक्सी बनाया जाएगा।

यदि आप CGLIB समीपता के उपयोग को बाध्य करना चाहते हैं (उदाहरण के लिए, लक्ष्य ऑब्जेक्ट के लिए परिभाषित प्रत्येक विधि को प्रॉक्सी करने के लिए, न कि केवल इसके इंटरफेस द्वारा लागू किए गए) तो आप ऐसा कर सकते हैं। हालाँकि, विचार करने के लिए कुछ मुद्दे हैं:

अंतिम तरीकों की सलाह नहीं दी जा सकती है, क्योंकि वे ओवरराइड नहीं हो सकते हैं।

आपको अपने क्लासपाथ पर CGLIB 2 बायनेरिज़ की आवश्यकता होगी, जबकि गतिशील परदे के पीछे JDK के साथ उपलब्ध हैं। स्प्रिंग को स्वचालित रूप से आपको चेतावनी दी जाएगी जब उसे सीजीएलआईबी की आवश्यकता होगी और सीजीएलआईबी पुस्तकालय कक्षाएं क्लासपाथ पर नहीं मिलती हैं।

आपकी अनुमानित वस्तु के निर्माता को दो बार कहा जाएगा। यह CGLIB प्रॉक्सी मॉडल का एक स्वाभाविक परिणाम है जिसके तहत प्रत्येक अनुमानित ऑब्जेक्ट के लिए एक उपवर्ग उत्पन्न होता है। प्रत्येक अनुमानित उदाहरण के लिए, दो ऑब्जेक्ट बनाए जाते हैं: वास्तविक अनुमानित ऑब्जेक्ट और उप-वर्ग का एक उदाहरण जो सलाह को लागू करता है। JDK परदे के पीछे का उपयोग करते समय इस व्यवहार का प्रदर्शन नहीं किया जाता है। आमतौर पर, दो बार अनुमानित प्रकार के कंस्ट्रक्टर को कॉल करना कोई समस्या नहीं है, क्योंकि आमतौर पर केवल असाइनमेंट होते हैं और कंस्ट्रक्टर में कोई वास्तविक तर्क लागू नहीं होता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.