2010-12-09 12 views
145

यदि मेरे पास @Transactional है- स्प्रिंग बीन में एक निजी विधि पर टिप्पणी, क्या एनोटेशन का कोई प्रभाव पड़ता है?क्या स्प्रिंग @ ट्रान्सएक्शनल विशेषता एक निजी विधि पर काम करती है?

यदि @Transactional एनोटेशन सार्वजनिक विधि पर है, तो यह कार्य करता है और एक लेनदेन खोलता है।

public class Bean { 
    public void doStuff() { 
    doPrivateStuff(); 
    } 
    @Transactional 
    private void doPrivateStuff() { 

    } 
} 

... 

Bean bean = (Bean)appContext.getBean("bean"); 
bean.doStuff(); 

उत्तर

172

आपके प्रश्न का उत्तर नहीं है - @Transactional अगर निजी तरीकों पर टिप्पणी करने के लिए इस्तेमाल कोई प्रभाव नहीं पड़ेगा। प्रॉक्सी जनरेटर उन्हें अनदेखा कर देगा।

यह Spring Manual chapter 10.5.6 में दर्ज है:

विधि दृश्यता और @Transactional

प्रॉक्सी का उपयोग करते समय, आप सार्वजनिक दृश्यता के साथ तरीकों के @Transactional एनोटेशन केवल लागू करना चाहिए। अगर आप ऐसा करेंगे व्याख्या, संरक्षित निजी या पैकेज दृश्य @Transactional टिप्पणी के साथ तरीकों, कोई त्रुटि उठाया है, लेकिन एनोटेट विधि कॉन्फ़िगर किया गया व्यवहार सेटिंग्स प्रदर्शन नहीं करता। गैर-सार्वजनिक तरीकों को एनोटेट करने के लिए की आवश्यकता होने पर AspectJ (नीचे देखें) का उपयोग करें।

+0

क्या आप इस बारे में निश्चित हैं? मैं इससे कोई फर्क नहीं पड़ता। – willcodejavaforfood

+27

हालांकि यह मोड = "aspectj" के साथ काम करेगा हालांकि। – waxwing

+1

@ विल्लकोडावाफॉर्फूड: उद्धरण देखें – skaffman

23

पर एक अंतरफलक, एक वर्ग परिभाषा है, या एक सार्वजनिक पद्धति पर, एक अंतरफलक परिभाषा के समक्ष रखा जा सकता है एक तरीका है डिफ़ॉल्ट रूप से @Transactional विशेषता केवल एप्लिकेशन कॉन्टेक्स्ट से प्राप्त संदर्भ पर एक एनोटेटेड विधि को कॉल करते समय काम करती है।

public class Bean { 
    public void doStuff() { 
    doTransactionStuff(); 
    } 
    @Transactional 
    public void doTransactionStuff() { 

    } 
} 

यह एक सौदे खुल जाएगा:

Bean bean = (Bean)appContext.getBean("bean"); 
bean.doTransactionStuff(); 

यह कार्य नहीं करेंगे:

Bean bean = (Bean)appContext.getBean("bean"); 
bean.doStuff(); 

Spring Reference: Using @Transactional

नोट: प्रॉक्सी मोड (जो डिफ़ॉल्ट है) में, प्रॉक्सी के माध्यम से आने वाली केवल 'बाहरी' विधि कॉल होगी अवरुद्ध किया जाना चाहिए। इसका मतलब है कि 'स्वयं-आमंत्रण', यानी लक्षित वस्तु के भीतर किसी अन्य विधि को लक्षित करने वाले लक्ष्य ऑब्जेक्ट के भीतर एक विधि, रनटाइम पर वास्तविक लेनदेन नहीं लेगी, भले ही चालित विधि @Transactional के साथ चिह्नित हो!

यदि आप स्वयं-चालान लेन-देन के साथ लपेटने की अपेक्षा करते हैं तो AspectJ मोड (नीचे देखें) के उपयोग पर विचार करें। इस मामले में, पहली जगह प्रॉक्सी नहीं होगी; इसके बजाए, किसी भी प्रकार की विधि पर रनटाइम व्यवहार में @Transactional को चालू करने के लिए लक्षित वर्ग 'weaved' (यानी इसके बाइट कोड संशोधित किया जाएगा) होगा।

+0

क्या आपका मतलब बीन = नया बीन() ;? – willcodejavaforfood

+0

नहीं। अगर मैं नए बीन() के साथ सेम बना देता हूं, तो एनोटेशन कम से कम आस्पेक्ट-जे का उपयोग किए बिना काम नहीं करेगा। –

+1

धन्यवाद! यह अजीब व्यवहार बताता है कि मैं देख रहा था। काफी आंतरिक काउंटर इन आंतरिक विधि आमंत्रण प्रतिबंध ... –

3

आपने जो इस डॉक देखें: प्रॉक्सी मोड में

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

यदि आप स्व-चालान लेन-देन के साथ लपेटने की अपेक्षा करते हैं तो AspectJ मोड (नीचे तालिका में मोड विशेषता देखें) के उपयोग पर विचार करें। इस मामले में, पहली जगह प्रॉक्सी नहीं होगी; इसके बजाए, किसी भी प्रकार की विधि पर @Transactional को रनटाइम व्यवहार में बदलने के लिए लक्षित वर्ग को बुनाया जाएगा (यानी, इसका बाइट कोड संशोधित किया जाएगा)।

---------------------------- से अधिक

हां, पराग-कोश तरह से उपयोगकर्ता BeanSelfAware

84

है प्रश्न निजी या सार्वजनिक नहीं है, सवाल यह है कि: इसे कैसे लागू किया जाता है और आप किस एओपी कार्यान्वयन का उपयोग करते हैं!

यदि आप स्प्रिंग प्रॉक्सी एओपी (डिफ़ॉल्ट) का उपयोग करते हैं, तो वसंत द्वारा प्रदान की गई सभी एओपी कार्यक्षमता (जैसे @Transational) केवल कॉल को प्रॉक्सी से गुजरने पर ही ध्यान में रखा जाएगा। - यह आमतौर पर मामला है यदि एनोटेटेड विधि से बीन से लागू की जाती है।

यह दो निहितार्थ हैं:

  • निजी विधियों (अपवाद प्रतिबिंब है) एक और सेम से लागू नहीं किया जाना चाहिए, क्योंकि उनके @Transactional एनोटेशन को ध्यान में रखा नहीं है।
  • यदि विधि सार्वजनिक है, लेकिन इसे उसी बीन से बुलाया जाता है, तो इसे ध्यान में नहीं रखा जाएगा (यह कथन केवल तभी सही होगा जब (डिफ़ॉल्ट) स्प्रिंग प्रॉक्सी एओपी का उपयोग किया जाता है)।

@See Spring Reference: Chapter 9.6 9.6 Proxying mechanisms

IMHO आप AspectJ मोड का उपयोग करना चाहिए, स्प्रिंग प्रॉक्सी के बजाय, कि समस्या को दूर करेगा। और AspectJ ट्रांजेक्शनल पहलुओं को भी निजी तरीकों से बुना जाता है (स्प्रिंग 3.0 के लिए जाँच की जाती है)।

+0

अच्छा (+1) लेकिन मुझे कुछ वर्तनी और व्याकरण संपादित करना पड़ा –

+0

दोनों बिंदु जरूरी नहीं हैं। पहला गलत है - निजी विधियों * को प्रतिबिंबित किया जा सकता है, लेकिन तर्क खोजने वाली प्रॉक्सी ऐसा करने का विकल्प नहीं चुनती है। दूसरा बिंदु केवल इंटरफ़ेस-आधारित जेडीके प्रॉक्सी के लिए सच है, लेकिन CGLIB सबक्लास-आधारित प्रॉक्सी के लिए नहीं। – skaffman

+0

@ स्काफमैन: 1 - मैं अपना स्टेटमेंट अधिक सटीक बना देता हूं, 2. लेकिन डिफ़ॉल्ट प्रॉक्सी इंटरफ़ेस आधारित है - है ना? – Ralph

8

हां, निजी तरीकों पर @ ट्रांसेक्शनल का उपयोग करना संभव है, लेकिन जैसा कि अन्य ने उल्लेख किया है कि यह बॉक्स से बाहर नहीं होगा। आपको AspectJ का उपयोग करने की आवश्यकता है। मुझे यह समझने में कुछ समय लगा कि यह कैसे काम कर रहा है। मैं अपने परिणाम साझा करूंगा।

मैंने लोड-टाइम बुनाई के बजाय संकलन-समय बुनाई का उपयोग करना चुना क्योंकि मुझे लगता है कि यह एक बेहतर विकल्प है। इसके अलावा, मैं जावा 8 का उपयोग कर रहा हूं ताकि आपको कुछ पैरामीटर समायोजित करने की आवश्यकता हो।

सबसे पहले, aspectjrt के लिए निर्भरता जोड़ें।

<dependency> 
    <groupId>org.aspectj</groupId> 
    <artifactId>aspectjrt</artifactId> 
    <version>1.8.8</version> 
</dependency> 

फिर मेवेन में वास्तविक बाइटकोड बुनाई करने के लिए AspectJ प्लगइन जोड़ें (यह एक न्यूनतम उदाहरण नहीं हो सकता है)।

<plugin> 
    <groupId>org.codehaus.mojo</groupId> 
    <artifactId>aspectj-maven-plugin</artifactId> 
    <version>1.8</version> 
    <configuration> 
     <complianceLevel>1.8</complianceLevel> 
     <source>1.8</source> 
     <target>1.8</target> 
     <aspectLibraries> 
      <aspectLibrary> 
       <groupId>org.springframework</groupId> 
       <artifactId>spring-aspects</artifactId> 
      </aspectLibrary> 
     </aspectLibraries> 
    </configuration> 
    <executions> 
     <execution> 
      <goals> 
       <goal>compile</goal> 
      </goals> 
     </execution> 
    </executions> 
</plugin> 

अंत में अपने config वर्ग

@EnableTransactionManagement(mode = AdviceMode.ASPECTJ) 

में जोड़ना अब आप निजी तरीकों पर @Transactional उपयोग करने के लिए सक्षम होना चाहिए।

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

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