Esegui il metodo all’avvio in spring

Esiste qualche funzionalità di Spring 3 per eseguire alcuni metodi all’avvio dell’applicazione per la prima volta? So che posso fare il trucco di impostare un metodo con @Scheduled annotazione @Scheduled e viene eseguito subito dopo l’avvio, ma poi verrà eseguito periodicamente.

Se per “avvio dell’applicazione” intendi “avvio contesto applicazione”, allora sì, ci sono molti modi per farlo , il più semplice (per i fagioli singleton, ad ogni modo) è quello di annotare il tuo metodo con @PostConstruct . Dai un’occhiata al link per vedere le altre opzioni, ma in sintesi sono:

  • Metodi annotati con @PostConstruct
  • afterPropertiesSet() come definito dall’interfaccia di callback InitializingBean
  • Un metodo init () personalizzato configurato

Tecnicamente, questi sono gli hook nel ciclo di vita dei bean , piuttosto che il ciclo di vita del contesto, ma nel 99% dei casi, i due sono equivalenti.

Se è necessario colbind in modo specifico l’avvio / arresto del contesto, è ansible implementare l’interfaccia del Lifecycle , ma probabilmente non è necessario.

Questo è fatto facilmente con un ApplicationListener . Ho fatto in modo che funzionasse ascoltando Spring’s ContextRefreshedEvent :

 import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.stereotype.Component; @Component public class StartupHousekeeper implements ApplicationListener { @Override public void onApplicationEvent(final ContextRefreshedEvent event) { // do whatever you need here } } 

Gli ascoltatori di applicazioni vengono eseguiti in modo sincrono in spring. Se vuoi assicurarti che il codice venga eseguito una volta sola, mantieni uno stato nel componente.

AGGIORNARE

A partire da Spring 4.2+ puoi anche usare l’annotazione @EventListener per osservare ContextRefreshedEvent (grazie a @bphilipnyc per averlo indicato):

 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 } } 

Nella spring 4.2+ ora puoi semplicemente fare:

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

Per gli utenti di Java 1.8 che ricevono un messaggio di avviso quando si tenta di fare riferimento all’annotazione @PostConstruct, ho finito con il piggybacking sull’annotazione @Scheduled che è ansible eseguire se si dispone già di un processo @Scheduled con fixedRate o fixedDelay.

 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"); } } 

Se usi lo spring-boot, questa è la migliore risposta.

Ritengo che @PostConstruct e altre varie interazioni del ciclo di vita siano modi di arrotondamento. Questi possono portare direttamente a problemi di runtime o causare meno di difetti evidenti a causa di eventi di ciclo di vita di bean / contesto imprevisti. Perché non invocare direttamente il tuo bean usando semplicemente Java? Continui a invocare il bean come “spring way” (es: attraverso il proxy AoP di spring). E soprattutto, è semplice java, non può essere più semplice di così. Non c’è bisogno di ascoltatori di contesto o programmatori dispari.

 @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(); } } 

Quello che abbiamo fatto è stato estendere org.springframework.web.context.ContextLoaderListener per stampare qualcosa all’avvio del contesto.

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

Configura la sottoclass quindi in web.xml :

   com.mycomp.myapp.web.context.ContextLoaderListener   

Attenzione, questo è solo consigliato se il metodo runOnceOnStartup dipende da un contesto di molla completamente inizializzato. Ad esempio: si desidera chiamare un dao con la demarcazione delle transazioni

Puoi anche usare un metodo programmato con fixedDelay impostato molto alto

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

Questo ha il vantaggio che l’intera applicazione è cablata (Transazioni, Dao, …)

visto in Pianificazione delle attività da eseguire una volta, utilizzando lo spazio dei nomi dell’attività Spring

Pubblicata un’altra soluzione che implementa WebApplicationInitializer e viene chiamata molto prima dell’istanza di qualsiasi bean spring, nel caso in cui qualcuno abbia quel caso d’uso

Inizializza impostazioni internazionali e fuso orario predefinite con la configurazione Spring

Se si desidera configurare un bean prima che l’applicazione sia completamente funzionante, è ansible utilizzare @Autowired :

 @Autowired private void configureBean(MyBean: bean) { bean.setConfiguration(myConfiguration); } 
 AppStartListener implements ApplicationListener { @Override public void onApplicationEvent(ApplicationEvent event) { if(event instanceof ApplicationReadyEvent){ System.out.print("ciao"); } } } 

È ansible utilizzare @EventListener sul componente, che verrà richiamato dopo l’avvio del server e tutti i bean inizializzati.

 @EventListener public void onApplicationEvent(ContextClosedEvent event) { }