वसंत में स्टार्टअप पर विधि निष्पादित करें


176

क्या पहली बार आवेदन शुरू होने पर कुछ विधियों को निष्पादित करने के लिए कोई स्प्रिंग 3 सुविधा है? मुझे पता है कि मैं @Scheduledएनोटेशन के साथ एक विधि सेट करने की चाल कर सकता हूं और यह स्टार्टअप के ठीक बाद निष्पादित होता है, लेकिन फिर यह समय-समय पर निष्पादित होगा।


1
@Scheduled के साथ क्या ट्रिक है? मुझे यही चाहिए!
क्रिस्मार्क्स

जवाबों:


185

यदि "एप्लिकेशन स्टार्टअप" से आपका मतलब "एप्लिकेशन संदर्भ स्टार्टअप" है, तो हां, ऐसा करने के कई तरीके हैं , सबसे आसान (एकल बीन्स के लिए, वैसे भी) अपने तरीके से एनोटेट करें @PostConstruct। अन्य विकल्पों को देखने के लिए लिंक पर एक नज़र डालें, लेकिन सारांश में वे हैं:

  • तरीकों के साथ टिप्पणी की @PostConstruct
  • afterPropertiesSet()जैसा कि InitializingBeanकॉलबैक इंटरफ़ेस द्वारा परिभाषित किया गया है
  • एक कस्टम कॉन्फ़िगर इनिट () विधि

तकनीकी रूप से, ये संदर्भ जीवनचक्र के बजाय बीन जीवनचक्र में शामिल हैं, लेकिन 99% मामलों में, दोनों समान हैं।

यदि आपको विशेष रूप से संदर्भ स्टार्टअप / शटडाउन में हुक करने की आवश्यकता है, तो आप इसके बजाय इंटरफ़ेस को लागूLifecycle कर सकते हैं , लेकिन यह संभवतः अनावश्यक है।


7
मुझे काफी शोध के बाद अभी तक जीवनचक्र या स्मार्टलिफ़साइकल के कार्यान्वयन को देखना है। मुझे पता है कि यह एक साल पुराना है, लेकिन स्केफमैन यदि आपके पास कुछ भी है जिसे आप पोस्ट कर सकते हैं जो बहुत सराहना की जाएगी।

4
ऊपर दिए गए तरीके पूरे आवेदन के संदर्भ से पहले लागू किए गए हैं (जैसे / / लेन-देन के सीमांकन से पहले सेटअप किया गया है)।
हंस वेस्टरबेक

मैं जावा 1.8 में उपयोग @PostConstruct की कोशिश कर रहा एक अजीब चेतावनी मिलती है:Access restriction: The type PostConstruct is not accessible due to restriction on required library /Library/Java/JavaVirtualMachines/jdk1.8.0_05.jdk/Contents/Home/jre/lib/rt.jar
encrest

2
ऐसे महत्वपूर्ण मामले हैं जहां बीन और संदर्भ जीवनचक्र बहुत अलग हैं। जैसा कि @HansWesterbeek ने उल्लेख किया है कि यह पूरी तरह से तैयार होने पर निर्भर होने से पहले सेम को सेटअप किया जा सकता है। मेरी स्थिति में जेएमएस पर निर्भर एक सेम - यह पूरी तरह से निर्माण किया गया था, इसलिए इसकी @PostConstructविधि को बुलाया गया था, लेकिन जेएमएस इन्फ्रा-स्ट्रक्चर जिस पर अप्रत्यक्ष रूप से निर्भर करता था वह अभी तक पूरी तरह से वायर्ड नहीं था (और बसंत चुपचाप सब कुछ विफल रहा)। @EventListener(ApplicationReadyEvent.class)काम किए गए सभी चीजों पर स्विच करने पर ( ApplicationReadyEventवेनिला स्प्रिंग के लिए स्प्रिंग बूट विशिष्ट है स्टीफन का उत्तर देखें)।
जॉर्ज हॉकिंस

@ सैकमैन: क्या होगा अगर मेरे बीन को किसी बीन द्वारा संदर्भित नहीं किया गया है और मैं बीन को कहीं भी इस्तेमाल किए बिना इनिशियलाइज़ करना चाहता हूं
सागर खरब

104

यह आसानी से एक के साथ किया जाता है ApplicationListener। मुझे स्प्रिंग की बात सुनकर यह काम मिला है ContextRefreshedEvent:

import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

@Component
public class StartupHousekeeper implements ApplicationListener<ContextRefreshedEvent> {

  @Override
  public void onApplicationEvent(final ContextRefreshedEvent event) {
    // do whatever you need here 
  }
}

अनुप्रयोग श्रोता स्प्रिंग में समकालिक रूप से चलते हैं। यदि आप यह सुनिश्चित करना चाहते हैं कि आप कोड को केवल एक बार निष्पादित करें, तो बस अपने कंपोनेंट में कुछ स्थिति रखें।

अपडेट करें

स्प्रिंग 4.2+ के साथ शुरू करने से आप @EventListenerएनोटेशन का उपयोग कर सकते हैं निरीक्षण करने के लिए ContextRefreshedEvent( इस बिंदु को इंगित करने के लिए @bphilipnyc के लिए धन्यवाद ):

import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

@Component
public class StartupHousekeeper {

  @EventListener(ContextRefreshedEvent.class)
  public void contextRefreshedEvent() {
    // do whatever you need here 
  }
}

1
इसने मेरे लिए भी काम किया - एक बार के गैर-बीन इनिशियलाइज़ेशन के लिए एकदम सही।
रोरी हंटर

9
ContextStartedEventइसके बजाय एनबी उन लोगों के लिए उपयोग करना पसंद करता है, जो ईवेंट की आग से पहले श्रोता को जोड़ना मुश्किल है।
ऑरेंजडॉग

2
Howto कॉल @Autowired JPA repositopry ईवेंट में? रिपॉजिटरी शून्य है।
ई-इन्फोरमिला २३

मेरे लिए काम नहीं कर रहा है। मैं स्प्रिंग mvc 3 का उपयोग कर रहा हूं। यह मेथोड onApplicationEvent (___) तब शुरू नहीं होता है जब एप्लिकेशन शुरू होता है। कोई मदद। यहां मेरा कोड @Component public class AppStartListener लागू होता है ApplicationListener <ContextRefreshedEvent> {public void onApplicationEvent (अंतिम ContextRefreshedEvent Event {} System.out.println ("एप्लीकेशन इवेंट पर \ n \ n \ n"); }}
विश्वास त्यागी

@VishwasTyagi आप अपना कंटेनर कैसे शुरू करते हैं? क्या आपको यकीन है, आपका AppStartListener आपके घटक स्कैन का हिस्सा है?
स्टीफन हैबरल

38

स्प्रिंग 4.2+ में आप अब बस कर सकते हैं:

@Component
class StartupHousekeeper {

    @EventListener(ContextRefreshedEvent.class)
    public void contextRefreshedEvent() {
        //do whatever
    }
}

क्या यह गारंटी है कि यह श्रोता स्टार्टअप के बाद केवल एक बार ही आमंत्रित करता है?
gstackoverflow

नहीं, ऊपर मेरा जवाब देखिए। यह सुनने के लिए कि क्या यह पहली बार चल रहा है, अपने श्रोता में कुछ स्थिति रखें
स्टीफन हैबर

13

यदि आप स्प्रिंग-बूट का उपयोग कर रहे हैं, तो यह सबसे अच्छा जवाब है।

मुझे लगता है कि @PostConstructऔर अन्य विभिन्न जीवन चक्र व्यवधान गोल-गोल तरीके हैं। ये अनपेक्षित बीन / संदर्भ जीवनचक्र की घटनाओं के कारण सीधे रनटाइम मुद्दों का कारण बन सकते हैं या स्पष्ट दोषों से कम हो सकते हैं। सीधे सादे जावा का उपयोग करके अपने बीन को सीधे क्यों न करें? आप अभी भी सेम को 'स्प्रिंग वे' कहते हैं (जैसे: स्प्रिंग एओपी प्रॉक्सी के माध्यम से)। और सबसे अच्छा, यह सादे जावा है, इससे कोई भी सरल नहीं मिल सकता है। संदर्भ श्रोताओं या विषम अनुसूचियों की कोई आवश्यकता नहीं है।

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext app = SpringApplication.run(DemoApplication.class, args);

        MyBean myBean = (MyBean)app.getBean("myBean");

        myBean.invokeMyEntryPoint();
    }
}

5
यह सामान्य रूप से एक अच्छा विचार है, लेकिन एक एकीकरण परीक्षण से अपने वसंत आवेदन संदर्भ को शुरू करते समय, मुख्य कभी नहीं चलाया जाता है!
जोनास गीरगेट

@JonasGeiregat: प्लस, ऐसे अन्य परिदृश्य हैं जहां कोई भी नहीं है main(), उदाहरण के लिए एक एप्लिकेशन फ्रेमवर्क का उपयोग करते समय (उदाहरण के लिए JavaServer चेहरे)।
साल्के

9

जावा 1.8 उपयोगकर्ताओं के लिए जो @PostConstruct एनोटेशन को संदर्भित करने का प्रयास करते समय एक चेतावनी प्राप्त कर रहे हैं, मैंने @Scheduled एनोटेशन को बंद करने के बजाय समाप्त कर दिया है जो कि आप कर सकते हैं यदि आपके पास पहले से ही तयशुदा या फिक्स्डले के साथ @Scheduled जॉब है।

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@EnableScheduling
@Component
public class ScheduledTasks {

private static final Logger LOGGER = LoggerFactory.getLogger(ScheduledTasks.class);

private static boolean needToRunStartupMethod = true;

    @Scheduled(fixedRate = 3600000)
    public void keepAlive() {
        //log "alive" every hour for sanity checks
        LOGGER.debug("alive");
        if (needToRunStartupMethod) {
            runOnceOnlyOnStartup();
            needToRunStartupMethod = false;
        }
    }

    public void runOnceOnlyOnStartup() {
        LOGGER.debug("running startup job");
    }

}


7

हमने जो किया है वह org.springframework.web.context.ContextLoaderListenerसंदर्भ शुरू होने पर कुछ छापने के लिए किया गया था ।

public class ContextLoaderListener extends org.springframework.web.context.ContextLoaderListener
{
    private static final Logger logger = LoggerFactory.getLogger( ContextLoaderListener.class );

    public ContextLoaderListener()
    {
        logger.info( "Starting application..." );
    }
}

फिर उपवर्ग को कॉन्फ़िगर करें web.xml:

<listener>
    <listener-class>
        com.mycomp.myapp.web.context.ContextLoaderListener
    </listener-class>
</listener>

7

स्प्रिंगबूट के साथ, हम @EventListenerएनोटेशन के माध्यम से स्टार्टअप पर एक विधि निष्पादित कर सकते हैं

@Component
public class LoadDataOnStartUp
{   
    @EventListener(ApplicationReadyEvent.class)
    public void loadData()
    {
        // do something
    }
}

4

ध्यान दें, यह केवल सलाह दी जाती है यदि आपकी runOnceOnStartupविधि पूरी तरह से प्रारंभिक वसंत संदर्भ पर निर्भर करती है। उदाहरण के लिए: आप लेन-देन सीमांकन के साथ एक डाओ को कॉल करना चाहते हैं

आप तयशुदा विधि के साथ निर्धारित पद्धति का उपयोग भी कर सकते हैं

@Scheduled(fixedDelay = Long.MAX_VALUE)
public void runOnceOnStartup() {
    dosomething();
}

इससे यह लाभ होता है कि पूरा आवेदन तार-तार हो जाता है (लेन-देन, दाव, ...)

स्प्रिंग टास्क नेमस्पेस का उपयोग करके एक बार चलने वाले शेड्यूलिंग कार्यों में देखा गया


मैं उपयोग करने पर कोई फायदा नहीं देख रहा हूँ @PostConstruct?
विंब डेलाबॉव

@ImDeblauwe इस बात पर निर्भर करता है कि आप क्या करना चाहते हैं dosomething में) (Trasaction demarcation के साथ एक Autowired डाओ को कॉल करने के लिए पूरे संदर्भ की आवश्यकता है, न कि यह बीन
Joram

5
@ImDeblauwe '@PostConstruct' विधि में आग लगने पर आग लग जाती है, पूरे संदर्भ तैयार नहीं हो सकता है (fe Transaction management)
जोरम

इस पोस्ट में निर्माण या किसी इंटरफेस या घटनाओं से imo अधिक सुरुचिपूर्ण है
aliopi

1

किसी अन्य समाधान को पोस्ट किया जो WebApplicationInitializer को लागू करता है और किसी भी स्प्रिंग बीन को तुरंत देने से पहले इसे कॉल किया जाता है, यदि किसी के पास उपयोग का मामला है

स्प्रिंग कॉन्फ़िगरेशन के साथ डिफ़ॉल्ट लोकेल और टाइमज़ोन को प्रारंभ करें


1
AppStartListener implements ApplicationListener {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if(event instanceof ApplicationReadyEvent){
            System.out.print("ciao");

        }
    }
}

2
ApplicationReadyEvent वसंत 3 में वसंत बूट में नहीं है
जॉन मर्सियर

0

यदि आप अपने आवेदन को पूरी तरह से चलाने से पहले बीन को कॉन्फ़िगर करना चाहते हैं, तो आप इसका उपयोग कर सकते हैं @Autowired:

@Autowired
private void configureBean(MyBean: bean) {
    bean.setConfiguration(myConfiguration);
}

0

आप @EventListenerअपने घटक पर उपयोग कर सकते हैं , जो सर्वर शुरू होने के बाद लागू किया जाएगा और सभी बीन्स को आरंभीकृत किया जाएगा।

@EventListener
public void onApplicationEvent(ContextClosedEvent event) {

}

0

StartupHousekeeper.javaपैकेज में स्थित फ़ाइल के लिए com.app.startup,

इसमें ये करें StartupHousekeeper.java:

@Component
public class StartupHousekeeper {

  @EventListener(ContextRefreshedEvent.class)
  public void keepHouse() {
    System.out.println("This prints at startup.");
  }
}

और इसमें ये करें myDispatcher-servlet.java:

<?xml version="1.0" encoding="UTF-8"?>
<beans>

    <mvc:annotation-driven />
    <context:component-scan base-package="com.app.startup" />

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