क्यों @PostConstruct का उपयोग करें?


294

एक प्रबंधित बीन में, @PostConstructनियमित जावा ऑब्जेक्ट कंस्ट्रक्टर के बाद कहा जाता है।

मैं @PostConstructनियमित निर्माणकर्ता के बजाय बीन द्वारा इनिशियलाइज़ करने के लिए उपयोग क्यों करूँगा ?


4
मुझे यह धारणा मिली कि सामान्य रूप से निर्भरता को अनुमति देने के लिए निर्माता इंजेक्शन को प्राथमिकता दी गई थी final। उस पैटर्न को देखते हुए, @PostConstructजे 2 ईई में क्यों जोड़ा जा रहा है - उन्होंने निश्चित रूप से एक और उपयोग मामला देखा होगा?
mjaggard

जवाबों:


409
  • क्योंकि जब कंस्ट्रक्टर को बुलाया जाता है, तो बीन को अभी तक इनिशियलाइज़ नहीं किया जाता है - यानी कोई भी निर्भरता इंजेक्ट नहीं की जाती है। में @PostConstructविधि सेम पूरी तरह से आरंभ और आप निर्भरता का उपयोग कर सकते हैं।

  • क्योंकि यह अनुबंध है जो गारंटी देता है कि यह विधि केवल एक बार बीन जीवन चक्र में लागू की जाएगी। ऐसा हो सकता है (हालांकि संभावना नहीं है) कि एक बीन को कंटेनर में कई बार उसके आंतरिक काम में @PostConstructलगाया जाता है , लेकिन यह गारंटी देता है कि इसे केवल एक बार ही लागू किया जाएगा।


17
यदि कंस्ट्रक्टर स्वयं सभी निर्भरता को स्वीकार कर लेता है - तो बीन को कंस्ट्रक्टर में पूरी तरह से इनिशियलाइज़ भी किया जा सकता है (मैन्युअल रूप से सभी ऑटोवार्ड फ़ील्ड सेट करने के बाद)।
yair

7
ऐसा क्या है जिसमें बीन के निर्माता को एक से अधिक बार बुलाया जा सकता है?
यार

1
शायद "पैशन" जैसा कुछ। यदि कंटेनर डिस्क स्टोर पर बीन को स्टोर करने का फैसला करता है और फिर इसे वहां से पुनर्स्थापित करता है।
बूझो

13
ऐसा नहीं है कि कंस्ट्रक्टर को कई बार देखने की संभावना नहीं है। जब कंटेनर एक प्रॉक्सी को तत्काल चालू करता है, तो आप देखेंगे कि निर्माता को कम से कम एक बार प्रॉक्सी के लिए और एक बार असली बीन के लिए बुलाया जाता है।
मारकस

ध्यान दें कि जब पृष्ठ को सर्वर पुनः आरंभ करने के तुरंत बाद लोड किया जाता है तो @PostConstruct विधियां नहीं कहलाती हैं । (यह एक JBoss बग हो सकता है।)
डेव जार्विस

96

मुख्य समस्या यह है कि यह है:

एक निर्माता में, निर्भरता का इंजेक्शन अभी तक नहीं हुआ है *

* स्पष्ट रूप से कंस्ट्रक्टर इंजेक्शन को छोड़कर


वास्तविक दुनिया का उदाहरण:

public class Foo {

    @Inject
    Logger LOG;

    @PostConstruct
    public void fooInit(){
        LOG.info("This will be printed; LOG has already been injected");
    }

    public Foo() {
        LOG.info("This will NOT be printed, LOG is still null");
        // NullPointerException will be thrown here
    }
}

महत्वपूर्ण : @PostConstructऔर जावा 11 में@PreDestroy पूरी तरह से हटा दिया गया है

उनका उपयोग करते रहने के लिए, आपको अपनी निर्भरताओं में javax.annotation-api JAR जोड़ने की आवश्यकता होगी ।

Maven

<!-- https://mvnrepository.com/artifact/javax.annotation/javax.annotation-api -->
<dependency>
    <groupId>javax.annotation</groupId>
    <artifactId>javax.annotation-api</artifactId>
    <version>1.3.2</version>
</dependency>

Gradle

// https://mvnrepository.com/artifact/javax.annotation/javax.annotation-api
compile group: 'javax.annotation', name: 'javax.annotation-api', version: '1.3.2'

19
in a constructor, the injection of the dependencies has not yet occurred. सेटर या फील्ड इंजेक्शन के साथ सही है, लेकिन कंस्ट्रक्टर इंजेक्शन के साथ सही नहीं है।
एडम सिएमियन

@PostConstruct को जावा 11 में हटाए जाने के साथ, अब हम जावा 11 के साथ इस वास्तविक दुनिया के उदाहरण को कैसे संभाल सकते हैं?
tet

@tet जैसा कि उत्तर में बताया गया है, आपको javax.annotation-api लाइब्रेरी का उपयोग करने की आवश्यकता है। ये टिप्पणियां जावा 11 में हटा दिया गया है, लेकिन पहले से ही जावा 9. के बाद से बहिष्कृत कर दिया गया चिह्नित किया गया
नरेंद्र-चौधरी

63

यदि आपकी कक्षा निर्माणकर्ता में अपनी सभी शुरुआत करती है, तो @PostConstructवास्तव में बेमानी है।

हालाँकि, यदि आपकी कक्षा में सेटर विधियों का उपयोग करके अपनी निर्भरताएँ इंजेक्ट की जाती हैं, तो क्लास का निर्माता पूरी तरह से ऑब्जेक्ट को इनिशियलाइज़ नहीं कर सकता है, और कभी-कभी सभी सेटर विधियों को कॉल करने के बाद कुछ इनिशियलाइज़ेशन की आवश्यकता होती है, इसलिए उपयोग का मामला @PostConstruct


@ स्टाफ़मैन: मेरी तरफ से प्लस। अगर मैं डेटाबेस से प्राप्त मान के साथ एक इनपुटटेक्स्ट फ़ील्ड को इनिशियलाइज़ करना चाहता हूं, तो मैं इसे पोस्टकंस्ट्रक्ट की मदद से कर पा रहा हूं, लेकिन कंस्ट्रक्टर के अंदर भी ऐसा करने का प्रयास करने पर विफल हो जाता है। PostContruct के उपयोग के बिना आरंभ करने के लिए मुझे इसकी आवश्यकता है। यदि आपके पास समय है, तो क्या आप इसका उत्तर भी दे सकते हैं: stackoverflow.com/questions/27540573/…
शिरगिल फरहान

10

इस परिदृश्य पर विचार करें:

public class Car {
  @Inject
  private Engine engine;  

  public Car() {
    engine.initialize();  
  }
  ...
}

चूंकि फ़ील्ड इंजेक्शन से पहले कार को तत्काल किया जाना है, इंजेक्शन बिंदु इंजन कंस्ट्रक्टर के निष्पादन के दौरान अभी भी अशक्त है, जिसके परिणामस्वरूप NullPointerException है।

इस समस्या को Java कन्स्ट्रक्टर इंजेक्शन के लिए JSR-330 डिपेंडेंसी इंजेक्शन या Java @PostConstruct विधि एनोटेशन के लिए JSR 250 कॉमन एनोटेशन द्वारा हल किया जा सकता है ।

@PostConstruct

JSR-250 एनोटेशन के एक सामान्य सेट को परिभाषित करता है जिसे Java SE 6 में शामिल किया गया है।

PostConstruct एनोटेशन का उपयोग एक ऐसी विधि पर किया जाता है जिसे किसी भी आरंभीकरण को करने के लिए निर्भरता इंजेक्शन के बाद निष्पादित किया जाना चाहिए। वर्ग में सेवा में रखने से पहले इस विधि को लागू किया जाना चाहिए। यह एनोटेशन सभी वर्गों पर निर्भर होना चाहिए जो निर्भरता इंजेक्शन का समर्थन करते हैं।

JSR-250 चैप। 2.5 javax.annotation.PostConstruct

@PostConstruct एनोटेशन इंस्टेंस को इंस्टैंट करने के बाद निष्पादित किए जाने वाले तरीकों की परिभाषा के लिए अनुमति देता है और सभी इंजेक्शन का प्रदर्शन किया गया है।

public class Car {
  @Inject
  private Engine engine;  

  @PostConstruct
  public void postConstruct() {
    engine.initialize();  
  }
  ...
} 

कन्स्ट्रक्टर में इनिशियलाइजेशन करने के बजाय, कोड को @PostConstruct के साथ एनोटेट करने की विधि में ले जाया जाता है।

निर्माण के बाद के तरीकों का प्रसंस्करण @PostConstruct के साथ एनोटेट किए गए सभी तरीकों को खोजने और बदले में उन्हें लागू करने का एक सरल मामला है।

private  void processPostConstruct(Class type, T targetInstance) {
  Method[] declaredMethods = type.getDeclaredMethods();

  Arrays.stream(declaredMethods)
      .filter(method -> method.getAnnotation(PostConstruct.class) != null) 
      .forEach(postConstructMethod -> {
         try {
           postConstructMethod.setAccessible(true);
           postConstructMethod.invoke(targetInstance, new Object[]{});
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {      
          throw new RuntimeException(ex);
        }
      });
}

इंस्टेंटेशन और इंजेक्शन के पूरा होने के बाद निर्माण के बाद के तरीकों का प्रसंस्करण किया जाना चाहिए।


1

जब भी किसी प्रकार की समीपता या रीमोटिंग शामिल होती है, तो कंस्ट्रक्टर आधारित आरंभीकरण भी इरादा के अनुसार काम नहीं करेगा।

जब भी कोई ईजेबी डिसेर्लाइज़ हो जाता है, तब सीटी को बुलाया जाएगा, और जब भी इसके लिए एक नया प्रॉक्सी बनेगा ...

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