प्रॉक्सी डिज़ाइन पैटर्न के मामले में , JDK के डायनेमिक प्रॉक्सी और थर्ड पार्टी डायनामिक कोड जेनरेशन API जैसे कि CGLib में क्या अंतर है ?
दोनों दृष्टिकोणों का उपयोग करने के बीच अंतर क्या है और कब एक को दूसरे पर पसंद करना चाहिए?
प्रॉक्सी डिज़ाइन पैटर्न के मामले में , JDK के डायनेमिक प्रॉक्सी और थर्ड पार्टी डायनामिक कोड जेनरेशन API जैसे कि CGLib में क्या अंतर है ?
दोनों दृष्टिकोणों का उपयोग करने के बीच अंतर क्या है और कब एक को दूसरे पर पसंद करना चाहिए?
जवाबों:
JDK डायनेमिक प्रॉक्सी केवल इंटरफ़ेस द्वारा प्रॉक्सी कर सकता है (इसलिए आपके लक्ष्य वर्ग को इंटरफ़ेस लागू करने की आवश्यकता होती है, जिसे तब प्रॉक्सी क्लास द्वारा भी लागू किया जाता है)।
CGLIB (और javassist) सबक्लासिंग द्वारा एक प्रॉक्सी बना सकते हैं। इस परिदृश्य में प्रॉक्सी लक्ष्य वर्ग का एक उपवर्ग बन जाता है। इंटरफेस की जरूरत नहीं।
तो जावा डायनामिक प्रॉक्सी प्रॉक्सी कर सकती है: public class Foo implements iFoo
जहाँ CGLIB प्रॉक्सी कर सकती है:public class Foo
संपादित करें:
मुझे यह उल्लेख करना चाहिए कि क्योंकि javassist और CGLIB उपवर्ग का उपयोग करके प्रॉक्सी का उपयोग करते हैं, यही कारण है कि आप इस पर भरोसा करने वाले चौखटे का उपयोग करते समय अंतिम विधियों की घोषणा नहीं कर सकते हैं या वर्ग को अंतिम नहीं बना सकते हैं। यह इन पुस्तकालयों को आपकी कक्षा को उप-वर्ग करने और आपके तरीकों को ओवरराइड करने की अनुमति देने से रोक देगा।
कार्यक्षमता में अंतर
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 अब सक्रिय विकास के अधीन नहीं है।
डायनेमिक प्रॉक्सी: JDK परावर्तन एपीआई का उपयोग करके रनटाइम पर इंटरफेस का गतिशील कार्यान्वयन ।
उदाहरण: वसंत लेनदेन के लिए गतिशील परदे के पीछे का उपयोग करता है:
उत्पन्न प्रॉक्सी बीन के ऊपर आती है। यह बीन में पारम्परिक व्यवहार जोड़ता है। यहाँ प्रॉक्सी JDK परावर्तन एपीआई का उपयोग करके रनटाइम पर गतिशील रूप से उत्पन्न होता है।
जब कोई एप्लिकेशन बंद हो जाता है, तो प्रॉक्सी नष्ट हो जाएगी और हमारे पास फ़ाइल सिस्टम पर केवल इंटरफ़ेस और बीन होगा।
उपरोक्त उदाहरण में हमारे पास इंटरफ़ेस है। लेकिन इंटरफ़ेस के अधिकांश कार्यान्वयन में सबसे अच्छा नहीं है। तो सेम एक इंटरफ़ेस को लागू नहीं करता है, उस स्थिति में हम विरासत का उपयोग करते हैं:
इस तरह के परदे के पीछे उत्पन्न करने के लिए, स्प्रिंग CGLib नामक एक तृतीय पक्ष पुस्तकालय का उपयोग करता है ।
CGLib ( सी स्तोत्र जी eneration लिब rary) के शीर्ष पर बनाया गया है एएसएम , यह मुख्य रूप प्रॉक्सी का विस्तार सेम पैदा करते हैं और प्रॉक्सी तरीकों में सेम व्यवहार कहते हैं प्रयोग किया जाता है।
स्प्रिंग AOP किसी दिए गए लक्ष्य वस्तु के लिए प्रॉक्सी बनाने के लिए या तो JDK डायनेमिक प्रॉक्सी या CGLIB का उपयोग करता है। (जब भी आपके पास विकल्प हो JDK डायनेमिक प्रॉक्सी पसंद की जाती है)।
यदि लक्ष्य वस्तु को कम से कम एक इंटरफ़ेस पर लागू किया जाना है तो JDK डायनेमिक प्रॉक्सी का उपयोग किया जाएगा। लक्ष्य प्रकार द्वारा लागू किए गए सभी इंटरफेस अनुमानित होंगे। यदि लक्ष्य ऑब्जेक्ट किसी भी इंटरफेस को लागू नहीं करता है तो एक CGLIB प्रॉक्सी बनाया जाएगा।
यदि आप CGLIB समीपता के उपयोग को बाध्य करना चाहते हैं (उदाहरण के लिए, लक्ष्य ऑब्जेक्ट के लिए परिभाषित प्रत्येक विधि को प्रॉक्सी करने के लिए, न कि केवल इसके इंटरफेस द्वारा लागू किए गए) तो आप ऐसा कर सकते हैं। हालाँकि, विचार करने के लिए कुछ मुद्दे हैं:
अंतिम तरीकों की सलाह नहीं दी जा सकती है, क्योंकि वे ओवरराइड नहीं हो सकते हैं।
आपको अपने क्लासपाथ पर CGLIB 2 बायनेरिज़ की आवश्यकता होगी, जबकि गतिशील परदे के पीछे JDK के साथ उपलब्ध हैं। स्प्रिंग को स्वचालित रूप से आपको चेतावनी दी जाएगी जब उसे सीजीएलआईबी की आवश्यकता होगी और सीजीएलआईबी पुस्तकालय कक्षाएं क्लासपाथ पर नहीं मिलती हैं।
आपकी अनुमानित वस्तु के निर्माता को दो बार कहा जाएगा। यह CGLIB प्रॉक्सी मॉडल का एक स्वाभाविक परिणाम है जिसके तहत प्रत्येक अनुमानित ऑब्जेक्ट के लिए एक उपवर्ग उत्पन्न होता है। प्रत्येक अनुमानित उदाहरण के लिए, दो ऑब्जेक्ट बनाए जाते हैं: वास्तविक अनुमानित ऑब्जेक्ट और उप-वर्ग का एक उदाहरण जो सलाह को लागू करता है। JDK परदे के पीछे का उपयोग करते समय इस व्यवहार का प्रदर्शन नहीं किया जाता है। आमतौर पर, दो बार अनुमानित प्रकार के कंस्ट्रक्टर को कॉल करना कोई समस्या नहीं है, क्योंकि आमतौर पर केवल असाइनमेंट होते हैं और कंस्ट्रक्टर में कोई वास्तविक तर्क लागू नहीं होता है।