Esecuzione del codice dopo l'avvio di Spring Boot


211

Voglio eseguire il codice dopo che la mia app di avvio a molla inizia a monitorare una directory per le modifiche.

Ho provato a eseguire un nuovo thread ma i @Autowiredservizi non sono stati impostati a quel punto.

Sono stato in grado di trovare ApplicationPreparedEvent, che si attiva prima che @Autowiredvengano impostate le annotazioni. Idealmente, vorrei che l'evento si attivasse quando l'applicazione è pronta per elaborare le richieste http.

Esiste un evento migliore da utilizzare o un modo migliore di eseguire il codice dopo che l'applicazione è attiva in Spring-Boot ?



Spring boot fornisce due interfacce ApplicationRunner e CommandLineRunner che possono essere utilizzate quando si desidera eseguire il codice dopo l'avvio di Spring Boot. Puoi fare riferimento a questo articolo per un esempio di implementazione - jhooq.com/applicationrunner-spring-boot
Rahul Wagh

Risposte:


121

Provare:

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application extends SpringBootServletInitializer {

    @SuppressWarnings("resource")
    public static void main(final String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);

        context.getBean(Table.class).fillWithTestdata(); // <-- here
    }
}

6
questo non funziona quando si distribuisce l'applicazione come file war su un tomcat esterno. Funziona solo con Tomcat incorporato
Saurabh

No, non funziona. Ma in questo caso d'uso mi piace un modo più esplicito invece di @Component. Vedi la risposta di @cjstehno per farlo funzionare in un file di guerra.
Anton Bessonov,

322

È semplice come questo:

@EventListener(ApplicationReadyEvent.class)
public void doSomethingAfterStartup() {
    System.out.println("hello world, I have just started up");
}

Testato sulla versione 1.5.1.RELEASE


7
grazie. questo ha fatto funzionare il mio codice senza alcuna modifica richiesta. Grazie ancora per una risposta così semplice. Funzionerà anche con l'annotazione @RequestMapping senza alcun problema.
Harshit,

16
Qualcuno potrebbe anche voler utilizzare @EventListener(ContextRefreshedEvent.class)invece, che viene attivato dopo la creazione del bean, ma prima dell'avvio del server. Può essere utilizzato per eseguire attività prima che qualsiasi richiesta raggiunga il server.
Neeraj,

3
@neeraj, la domanda riguarda l'esecuzione del codice dopo l'avvio di Spring Boot. Se lo usi ContextRefreshedEvent, verrà eseguito anche dopo ogni aggiornamento.
cahen,

4
testato su Spring boot 2.0.5.RELEASE
ritesh

2
Testato sulla versione 2.2.2. funziona perfettamente. questa soluzione mi fa risparmiare tempo.
Arphile il

96

Hai provato ApplicationReadyEvent?

@Component
public class ApplicationStartup 
implements ApplicationListener<ApplicationReadyEvent> {

  /**
   * This event is executed as late as conceivably possible to indicate that 
   * the application is ready to service requests.
   */
  @Override
  public void onApplicationEvent(final ApplicationReadyEvent event) {

    // here your code ...

    return;
  }
}

Codice da: http://blog.netgloo.com/2014/11/13/run-code-at-spring-boot-startup/

Questo è ciò che la documentazione menziona sugli eventi di avvio:

...

Gli eventi dell'applicazione vengono inviati nel seguente ordine, durante l'esecuzione dell'applicazione:

Un ApplicationStartedEvent viene inviato all'inizio di una corsa, ma prima di qualsiasi elaborazione eccetto la registrazione di listener e inizializzatori.

Un ApplicationEnvironmentPreparedEvent viene inviato quando l'ambiente da utilizzare nel contesto è noto, ma prima della creazione del contesto.

Un ApplicationPreparedEvent viene inviato subito prima dell'avvio dell'aggiornamento, ma dopo che le definizioni dei bean sono state caricate.

Un ApplicationReadyEvent viene inviato dopo l'aggiornamento e tutti i callback correlati sono stati elaborati per indicare che l'applicazione è pronta per soddisfare le richieste.

Viene inviato un ApplicationFailedEvent se si verifica un'eccezione all'avvio.

...


11
In alternativa, puoi farlo usando l' @EventListenerannotazione su un metodo Bean, passando come argomento l'evento di classe a cui vuoi agganciare.
padilo,

2
Questa dovrebbe essere la risposta scelta.
varun113,

2
Questo è cambiato in spring-boot 2. Se si esegue il porting da 1.x e si utilizzava ApplicationStartedEvent, ora si desidera invece ApplicationStartingEvent.
Andy Brown,

Funziona perfettamente e penso che sia il modo migliore per farlo.
AVINASH SHRIMALI,

tu sei il migliore
ancm

83

Perché non creare semplicemente un bean che avvia il monitor all'inizializzazione, qualcosa del tipo:

@Component
public class Monitor {
    @Autowired private SomeService service

    @PostConstruct
    public void init(){
        // start your monitoring in here
    }
}

il initmetodo non verrà chiamato fino a quando non viene eseguito alcun autowiring per il bean.


14
A volte @PostConstructspara troppo presto. Ad esempio, quando si utilizza Spring Cloud Stream Kafka, si @PostConstructattiva prima che l'applicazione si leghi a Kafka. La soluzione di Dave Syer è migliore perché si attiva tempestivamente.
Elnur Abdurrakhimov,

9
@PostConstructsuccede durante l'inizializzazione, non dopo. Anche se questo può essere utile in alcuni casi, non è la risposta corretta se si desidera eseguire dopo l' avvio di Spring Boot. Ad esempio, mentre @PostConstructnon termina, nessuno degli endpoint è disponibile.
Cahen,

63

Il modo "Spring Boot" è di usare a CommandLineRunner. Aggiungi solo fagioli di quel tipo e sei a posto. In Spring 4.1 (Boot 1.2) c'è anche un oggetto SmartInitializingBeanche riceve un callback dopo che tutto è stato inizializzato. E c'è SmartLifecycle(dalla primavera 3).


Qualche esempio di questo? È possibile eseguire un bean dopo che l'applicazione è in esecuzione, tramite riga di comando in un momento arbitrario?
Emilio,

5
Non so cosa intendi per "momento arbitrario". La guida per l'utente e gli esempi di Spring Boot contengono esempi di utilizzo di un CommandLineRunner(e del più recente ApplicationRunner): docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/… .
Dave Syer,

Ho scoperto che Lifecycle è l'opzione preferita per eseguire attività asincrone nelle fasi di avvio / arresto dell'applicazione e sto cercando di individuare altre differenze tra CommandLineRunner e InitializingBeans, ma non riesco a trovare nulla al riguardo.
saljuama,

3
coppia solito esempio di codice d'usoCommandLineRunner
Alexey Simonov

41

È possibile estendere una classe utilizzando ApplicationRunner, sovrascrivere il run()metodo e aggiungere il codice lì.

import org.springframework.boot.ApplicationRunner;

@Component
public class ServerInitializer implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments applicationArguments) throws Exception {

        //code goes here

    }
}

Perfetto in Spring Boot. Ma il metodo run () è stato chiamato due volte quando si utilizza ApplicationScope per la classe. Quindi il metodo PostConstruct con quanto sopra ha funzionato meglio.
Sam,

26

ApplicationReadyEventè davvero utile solo se l'attività che si desidera eseguire non è un requisito per il corretto funzionamento del server. L'avvio di un'attività asincrona per monitorare qualcosa per le modifiche è un buon esempio.

Se, tuttavia, il tuo server è in uno stato 'non pronto' fino al completamento dell'attività, è meglio implementarlo SmartInitializingSingletonperché otterrai la richiamata prima che la tua porta REST sia stata aperta e che il tuo server sia aperto per le imprese.

Non essere tentato di utilizzare @PostConstructper attività che dovrebbero avvenire una sola volta. Riceverai una brutta sorpresa quando noti che viene chiamato più volte ...


Questa dovrebbe essere la risposta scelta. Come sottolinea @Andy, SmartInitializingSingleton viene chiamato appena prima dell'apertura delle porte.
Srikanth,

25

Con configurazione a molla:

@Configuration
public class ProjectConfiguration {
    private static final Logger log = 
   LoggerFactory.getLogger(ProjectConfiguration.class);

   @EventListener(ApplicationReadyEvent.class)
   public void doSomethingAfterStartup() {
    log.info("hello world, I have just started up");
  }
}

12

Usa un SmartInitializingSingletonfagiolo in primavera> 4.1

@Bean
public SmartInitializingSingleton importProcessor() {
    return () -> {
        doStuff();
    };

}

In alternativa è CommandLineRunnerpossibile implementare un bean o annotare un metodo bean con @PostConstruct.


Posso richiedere una dipendenza Autowired all'interno di quel metodo? Vorrei impostare Profili
LppEdd il

7

Fornendo un esempio per la risposta di Dave Syer, che ha funzionato come un incantesimo:

@Component
public class CommandLineAppStartupRunner implements CommandLineRunner {
    private static final Logger logger = LoggerFactory.getLogger(CommandLineAppStartupRunner.class);

    @Override
    public void run(String...args) throws Exception {
        logger.info("Application started with command-line arguments: {} . \n To kill this application, press Ctrl + C.", Arrays.toString(args));
    }
}

7

Prova questo ed eseguirà il tuo codice quando il contesto dell'applicazione sarà completamente avviato.

 @Component
public class OnStartServer implements ApplicationListener<ContextRefreshedEvent> {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent arg0) {
                // EXECUTE YOUR CODE HERE 
    }
}

6

Mi piace molto il suggerimento per l'utilizzo EventListenerdell'annotazione di @cahen ( https://stackoverflow.com/a/44923402/9122660 ) poiché è molto pulito. Purtroppo non sono riuscito a farlo funzionare in una configurazione Spring + Kotlin. Ciò che funziona per Kotlin è l'aggiunta della classe come parametro del metodo:

@EventListener 
fun doSomethingAfterStartup(event: ApplicationReadyEvent) {
    System.out.println("hello world, I have just started up");
}

Mettilo nella classe dell'applicazione di avvio a molla non casualmente fuori lato@SpringBootApplication class MyApplication { @EventListener(ApplicationReadyEvent::class) fun doSomethingAfterStartup() { println("hello world, I have just started up") } }
Ahmed na

non è necessario inserirlo nella classe @SpringBootApplication. qualsiasi lezione di configurazione farà
George Marin il

5

Il modo migliore per eseguire il blocco di codice dopo l'avvio dell'applicazione Spring Boot consiste nell'utilizzare l'annotazione PostConstruct, oppure è possibile utilizzare il runner della riga di comando per lo stesso.

1. Usando l'annotazione PostConstruct

@Configuration
public class InitialDataConfiguration {

    @PostConstruct
    public void postConstruct() {
        System.out.println("Started after Spring boot application !");
    }

}

2. Utilizzo del bean runner della riga di comando

@Configuration
public class InitialDataConfiguration {

    @Bean
    CommandLineRunner runner() {
        return args -> {
            System.out.println("CommandLineRunner running in the UnsplashApplication class...");
        };
    }
}

3

basta implementare CommandLineRunner per l'applicazione di avvio a molla. È necessario implementare il metodo di esecuzione,

public classs SpringBootApplication implements CommandLineRunner{

    @Override
        public void run(String... arg0) throws Exception {
        // write your logic here 

        }
}

0

Il modo migliore di utilizzare CommandLineRunner o ApplicationRunner L'unica differenza tra il metodo run () CommandLineRunner accetta la matrice di stringhe e ApplicationRunner accetta ApplicationArugument.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.