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.