Je veux exécuter du code après que mon spring-boot app commence à surveiller un répertoire pour y apporter des modifications.
J'ai essayé de lancer un nouveau thread, mais les services @Autowired
n'ont pas encore été définis.
J'ai pu trouver ApplicationPreparedEvent
, qui se déclenche avant que les annotations @Autowired
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 requêtes http.
Existe-t-il un meilleur événement à utiliser ou un meilleur moyen d’exécuter du code une fois l’application installée dans spring-boot ?
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
}
}
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
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 de: http://blog.netgloo.com/2014/11/13/run-code-at-spring-boot-startup/
Voici ce que la documentation mentionne à propos des événements de démarrage:
...
Les événements d'application sont envoyés dans l'ordre suivant, au cours de l'exécution de votre application:
Un ApplicationStartedEvent est envoyé au début d'une exécution, mais avant tout traitement sauf l'enregistrement des écouteurs et des initialiseurs.
Un ApplicationEnvironmentPreparedEvent est envoyé lorsque l'environnement à utiliser dans le contexte est connu, mais avant le contexte est créé.
Un événement ApplicationPreparedEvent est envoyé juste avant le démarrage de l'actualisation, mais après le chargement des définitions de bean.
Un événement 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 à utiliser demandes de service.
Un ApplicationFailedEvent est envoyé s'il existe une exception au démarrage.
...
Pourquoi ne pas simplement créer un haricot qui démarre votre moniteur à l’initialisation, quelque chose comme:
@Component
public class Monitor {
@Autowired private SomeService service
@PostConstruct
public void init(){
// start your monitoring in here
}
}
la méthode init
ne sera pas appelée tant que le câblage automatique n'aura pas été effectué pour le bean.
La méthode "Spring Boot" consiste à utiliser une variable CommandLineRunner
. Ajoutez simplement des haricots de ce type et vous êtes prêt à partir. Dans Spring 4.1 (Boot 1.2), il existe également une SmartInitializingBean
qui reçoit un rappel une fois que tout est initialisé. Et il y a SmartLifecycle
(à partir du printemps 3).
Vous pouvez étendre une classe en utilisant ApplicationRunner
, substituer la méthode run()
et ajouter le code à cet endroit.
import org.springframework.boot.ApplicationRunner;
@Component
public class ServerInitializer implements ApplicationRunner {
@Override
public void run(ApplicationArguments applicationArguments) throws Exception {
//code goes here
}
}
ApplicationReadyEvent
n'est utile que si la tâche que vous voulez effectuer n'est pas une condition requise pour un fonctionnement correct du serveur. Démarrer une tâche asynchrone pour surveiller quelque chose pour des modifications est un bon exemple.
Si, toutefois, votre serveur est dans un état "pas prêt" jusqu'à la fin de la tâche, il est préférable d'implémenter SmartInitializingSingleton
car vous obtiendrez le rappel avant votre port REST a été ouvert et votre serveur Ouvert pour les affaires.
Ne soyez pas tenté d'utiliser @PostConstruct
pour des tâches qui ne devraient se produire qu'une seule fois. Vous aurez une surprise désagréable lorsque vous remarquerez qu'il est appelé plusieurs fois ...
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");
}
}
Utilisez un haricot SmartInitializingSingleton
au printemps> 4.1
@Bean
public SmartInitializingSingleton importProcessor() {
return () -> {
doStuff();
};
}
Comme alternative, un bean CommandLineRunner
peut être implémenté ou annoter une méthode de bean avec @PostConstruct
.
Voici un exemple de réponse de Dave Syer, qui a fonctionné à merveille:
@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));
}
}
il suffit d'implémenter CommandLineRunner pour une application de démarrage printanier . Vous devez implémenter une méthode d'exécution,
public classs SpringBootApplication implements CommandLineRunner{
@Override
public void run(String... arg0) throws Exception {
// write your logic here
}
}
Essayez celui-ci et il exécutera votre code lorsque le contexte de l'application aura complètement démarré.
@Component
public class OnStartServer implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent arg0) {
// EXECUTE YOUR CODE HERE
}
}
Le meilleur moyen d'exécuter un bloc de code après le démarrage de l'application Spring Boot consiste à utiliser annotation PostConstruct. Vous pouvez également utiliser le programme d'exécution 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 haricot de la ligne de commande
@Configuration
public class InitialDataConfiguration {
@Bean
CommandLineRunner runner() {
return args -> {
System.out.println("CommandLineRunner running in the UnsplashApplication class...");
};
}
}
J'aime beaucoup la suggestion d'utilisation de l'annotation EventListener
par @cahen ( https://stackoverflow.com/a/44923402/9122660 ) car elle est très propre. Malheureusement, je ne pouvais pas obtenir que cela fonctionne dans une configuration Spring + Kotlin. Ce qui fonctionne pour Kotlin ajoute la classe en tant que paramètre de méthode:
@EventListener
fun doSomethingAfterStartup(event: ApplicationReadyEvent) {
System.out.println("hello world, I have just started up");
}