Exécution de code après le démarrage de Spring Boot


211

Je souhaite exécuter du code après le démarrage de mon application Spring-Boot pour surveiller les modifications d'un répertoire.

J'ai essayé d'exécuter un nouveau thread mais les @Autowiredservices n'ont pas été définis à ce stade.

J'ai pu trouver ApplicationPreparedEventce qui se déclenche avant que les @Autowiredannotations ne soient définies. Idéalement, j'aimerais que l'événement se déclenche une fois que l'application est prête à traiter les demandes http.

Y a-t-il un meilleur événement à utiliser ou une meilleure façon d'exécuter du code après que l'application est en ligne au printemps ?



Spring Boot fournit deux interfaces ApplicationRunner et CommandLineRunner qui peuvent être utilisées lorsque vous souhaitez exécuter le code après le démarrage de Spring. Vous pouvez vous référer à cet article pour un exemple d'implémentation - jhooq.com/applicationrunner-spring-boot
Rahul Wagh

Réponses:


121

Essayer:

@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
cela ne fonctionne pas lorsque vous déployez l'application en tant que fichier war sur un tomcat externe. Il ne fonctionne qu'avec le tomcat intégré
Saurabh

Non, ça ne marche pas. Mais dans ce cas d'utilisation, j'aime de manière plus explicite au lieu de @Component. Voir la réponse de @cjstehno pour le faire fonctionner dans un fichier de guerre.
Anton Bessonov

322

C'est aussi simple que cela:

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

Testé sur la version 1.5.1.RELEASE


7
Merci. cela a fait fonctionner mon code sans aucun changement requis. Merci encore pour une réponse aussi simple. Cela fonctionnera également avec l'annotation @RequestMapping sans aucun problème.
Harshit

16
Quelqu'un peut également souhaiter l'utiliser à la @EventListener(ContextRefreshedEvent.class)place, ce qui est déclenché après la création du bean, mais avant le démarrage du serveur. Il peut être utilisé pour effectuer des activités avant que toute demande n'atteigne le serveur.
neeraj

3
@neeraj, la question porte sur l'exécution de code après le démarrage de Spring Boot. Si vous utilisez ContextRefreshedEvent, il s'exécutera également après chaque actualisation.
cahen

4
testé sur Spring boot 2.0.5.RELEASE
ritesh

2
Testé sur la version 2.2.2. cela fonctionne parfaitement. cette solution me fait gagner du temps.
Arphile

96

Avez-vous essayé 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;
  }
}

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

Voici ce que la documentation mentionne sur les événements de démarrage:

...

Les événements d'application sont envoyés dans l'ordre suivant lors de l'exécution de votre application:

Un ApplicationStartedEvent est envoyé au début d'une exécution, mais avant tout traitement, à l'exception de l'enregistrement des écouteurs et des initialiseurs.

Un ApplicationEnvironmentPreparedEvent est envoyé lorsque l'environnement à utiliser dans le contexte est connu, mais avant la création du contexte.

Un ApplicationPreparedEvent est envoyé juste avant le démarrage de l'actualisation, mais après le chargement des définitions de bean.

Un ApplicationReadyEvent est envoyé après l'actualisation et tous les rappels associés ont été traités pour indiquer que l'application est prête à répondre aux demandes.

Un ApplicationFailedEvent est envoyé s'il existe une exception au démarrage.

...


11
Comme alternative, vous pouvez le faire en utilisant une @EventListenerannotation sur une méthode Bean, en passant comme argument l'événement de classe auquel vous souhaitez vous accrocher.
padilo

2
Ce devrait être la réponse choisie.
varun113

2
Cela a changé dans spring-boot 2. Si vous effectuez un portage à partir de 1.x et que vous utilisiez ApplicationStartedEvent, vous voulez maintenant ApplicationStartingEvent à la place.
Andy Brown

Cela fonctionne très bien et je pense que la meilleure façon de le faire.
AVINASH SHRIMALI

vous êtes le meilleur
ancm

83

Pourquoi ne pas simplement créer un bean qui démarre votre moniteur lors de l'initialisation, quelque chose comme:

@Component
public class Monitor {
    @Autowired private SomeService service

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

la initméthode ne sera pas appelée tant que le câblage automatique n'aura pas été effectué pour le bean.


14
Tire parfois @PostConstructtrop tôt. Par exemple, lorsque vous utilisez Spring Cloud Stream Kafka, il se @PostConstructdéclenche avant que l'application ne se lie à Kafka. La solution de Dave Syer est meilleure car elle se déclenche en temps opportun.
Elnur Abdurrakhimov

9
@PostConstructse produit pendant l'initialisation, pas après. Bien que cela puisse être utile dans certains cas, ce n'est pas la bonne réponse si vous souhaitez exécuter après le démarrage de Spring Boot. Par exemple, bien qu'il @PostConstructne se termine pas, aucun des points de terminaison n'est disponible.
cahen

64

La méthode "Spring Boot" consiste à utiliser a CommandLineRunner. Ajoutez simplement des haricots de ce type et vous êtes prêt à partir. Dans Spring 4.1 (Boot 1.2), il y a aussi un SmartInitializingBeanqui reçoit un rappel après que tout a été initialisé. Et il y en a SmartLifecycle(à partir du printemps 3).


Un exemple de ça? Est-il possible d'exécuter un bean après l'exécution de l'application, via la ligne de commande à un moment arbitraire?
Emilio

5
Je ne sais pas ce que vous entendez par "moment arbitraire". Le guide d'utilisation et les exemples de Spring Boot contiennent des exemples d'utilisation d'un CommandLineRunner(et du plus récent ApplicationRunner): docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/… .
Dave Syer, du

J'ai trouvé que Lifecycle est l'option préférée pour effectuer des tâches asynchrones sur les étapes de démarrage / arrêt de l'application, et j'essaie de repérer d'autres différences entre CommandLineRunner et InitializingBeans, mais je ne trouve rien à ce sujet.
saljuama

3
exemple de code d'utilisation habituelCommandLineRunner
Alexey Simonov

41

Vous pouvez étendre une classe à l'aide de ApplicationRunner, remplacer la run()méthode et y ajouter le code.

import org.springframework.boot.ApplicationRunner;

@Component
public class ServerInitializer implements ApplicationRunner {

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

        //code goes here

    }
}

Parfait dans Spring Boot. Mais la méthode run () a été appelée deux fois avec ApplicationScope pour la classe. La méthode PostConstruct avec ce qui précède a donc mieux fonctionné.
Sam

26

ApplicationReadyEventn'est vraiment utile que si la tâche que vous souhaitez effectuer n'est pas requise pour un fonctionnement correct du serveur. Le démarrage d'une tâche asynchrone pour surveiller quelque chose pour les changements est un bon exemple.

Si, cependant, votre serveur est dans un état `` non prêt '' jusqu'à ce que la tâche soit terminée, il est préférable de l'implémenter SmartInitializingSingletoncar vous recevrez le rappel avant l' ouverture de votre port REST et votre serveur est ouvert pour les entreprises.

Ne soyez pas tenté d'utiliser @PostConstructpour des tâches qui ne devraient se produire qu'une seule fois. Vous aurez une grossière surprise lorsque vous remarquerez qu'il est appelé plusieurs fois ...


Ce devrait être la réponse choisie. Comme le souligne @Andy, SmartInitializingSingleton est appelé juste avant l'ouverture des ports.
Srikanth

25

Avec configuration à ressort:

@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

Utilisez un SmartInitializingSingletonharicot au printemps> 4,1

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

}

Comme alternative, un CommandLineRunnerbean peut être implémenté ou annoter une méthode de bean avec @PostConstruct.


Puis-je exiger une dépendance Autowired à l'intérieur de cette méthode? Je voudrais définir des profils
LppEdd

7

Voici un exemple de réponse de Dave Syer, qui a fonctionné comme un charme:

@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

Essayez celui-ci et il exécutera votre code lorsque le contexte d'application aura complètement démarré.

 @Component
public class OnStartServer implements ApplicationListener<ContextRefreshedEvent> {

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

6

J'aime vraiment la suggestion d'utilisation de l' EventListenerannotation par @cahen ( https://stackoverflow.com/a/44923402/9122660 ) car elle est très propre. Malheureusement, je n'ai pas pu faire fonctionner cela dans une configuration Spring + Kotlin. Ce qui fonctionne pour Kotlin, c'est l'ajout de la classe comme paramètre de méthode:

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

Mettez-le dans la classe d'application de démarrage de printemps pas au hasard@SpringBootApplication class MyApplication { @EventListener(ApplicationReadyEvent::class) fun doSomethingAfterStartup() { println("hello world, I have just started up") } }
Ahmed na

vous n'avez pas besoin de le mettre nécessaire à la classe @SpringBootApplication. n'importe quelle classe de configuration fera l'affaire
George Marin

5

La meilleure façon d'exécuter un bloc de code après le démarrage de l'application Spring Boot est d'utiliser l'annotation PostConstruct, ou vous pouvez également utiliser un exécuteur de ligne de commande pour la même chose.

1. Utilisation de l'annotation PostConstruct

@Configuration
public class InitialDataConfiguration {

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

}

2. Utilisation du bean runner de ligne de commande

@Configuration
public class InitialDataConfiguration {

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

3

implémentez simplement CommandLineRunner pour l’application Spring Boot. Vous devez implémenter la méthode d'exécution,

public classs SpringBootApplication implements CommandLineRunner{

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

        }
}

0

Meilleure façon d'utiliser CommandLineRunner ou ApplicationRunner La seule différence entre la méthode run () est que CommandLineRunner accepte un tableau de chaînes et ApplicationRunner accepte ApplicationArugument.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.