Existe-t-il une fonctionnalité Spring 3 permettant d'exécuter certaines méthodes lorsque l'application démarre pour la première fois? Je sais que je peux faire l'astuce en définissant une méthode avec l'annotation @Scheduled
et qu'elle s'exécute juste après le démarrage, mais elle s'exécutera périodiquement.
Si par "démarrage de l'application" vous voulez dire "démarrage du contexte de l'application", alors oui, il y a de nombreuses façons de faire cela , le plus simple (pour les beans singletons de toute façon) consiste à annoter votre méthode avec @PostConstruct
. Regardez le lien pour voir les autres options, mais en résumé, elles sont:
@PostConstruct
afterPropertiesSet()
tel que défini par l'interface de rappel InitializingBean
Techniquement, ce sont des points d'ancrage dans le cycle de vie bean, plutôt que dans le contexte, mais dans 99% des cas, les deux sont équivalents.
Si vous devez vous attacher spécifiquement au démarrage/à l'arrêt du contexte, vous pouvez implémenter l'interface Lifecycle
à la place, mais c'est probablement inutile.
Cela se fait facilement avec un ApplicationListener
. Je suis au travail en écoutant la ContextRefreshedEvent
de Spring:
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
@Component
public class StartupHousekeeper implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(final ContextRefreshedEvent event) {
// do whatever you need here
}
}
Les écouteurs d'application fonctionnent de manière synchrone au printemps. Si vous voulez vous assurer que votre code n'est exécuté qu'une seule fois, conservez simplement un état dans votre composant.
METTRE &AGRAVE; JOUR
À partir de Spring 4.2+, vous pouvez également utiliser l'annotation @EventListener
pour observer la ContextRefreshedEvent
(merci à @bphilipnyc de l'avoir signalé):
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
}
}
Au printemps 4.2+, vous pouvez maintenant faire simplement:
@Component
class StartupHousekeeper {
@EventListener(ContextRefreshedEvent.class)
void contextRefreshedEvent() {
//do whatever
}
}
Pour les utilisateurs de Java 1.8 qui reçoivent un avertissement lorsqu'ils tentent de référencer l'annotation @PostConstruct, je me suis plutôt retrouvé à greffer l'annotation @Scheduled que vous pouvez effectuer si vous avez déjà un travail @Scheduled avec fixedRate ou 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");
}
}
Si vous utilisez Spring-Boot, c'est la meilleure réponse.
Je pense que @PostConstruct
et d'autres interjections de cycles de vie variés sont des moyens détournés. Celles-ci peuvent entraîner directement des problèmes d'exécution ou entraîner des défauts moins qu'évidents en raison d'événements de cycle de vie de bean/contexte inattendus. Pourquoi ne pas simplement invoquer directement votre bean à l'aide de Java pur? Vous invoquez toujours le haricot à la «source printanière» (par exemple, via le proxy AoP du printemps). Et le meilleur de tous, il est clair Java, ne peut pas être plus simple que cela. Pas besoin d'écoute de contexte ou d'ordonnanceurs impairs.
@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();
}
}
Nous avons étendu org.springframework.web.context.ContextLoaderListener
pour imprimer quelque chose au début du contexte.
public class ContextLoaderListener extends org.springframework.web.context.ContextLoaderListener
{
private static final Logger logger = LoggerFactory.getLogger( ContextLoaderListener.class );
public ContextLoaderListener()
{
logger.info( "Starting application..." );
}
}
Configurez la sous-classe puis dans web.xml
:
<listener>
<listener-class>
com.mycomp.myapp.web.context.ContextLoaderListener
</listener-class>
</listener>
Attention, ceci n’est conseillé que si votre méthode
runOnceOnStartup
dépend de contexte de printemps totalement initialisé. Par exemple: vous voulez appeler un dao avec démarcation des transactions
Vous pouvez également utiliser une méthode planifiée avec fixedDelay très élevé
@Scheduled(fixedDelay = Long.MAX_VALUE)
public void runOnceOnStartup() {
dosomething();
}
Cela a l'avantage que toute l'application est câblée (Transactions, Dao, ...)
vu dans Planification des tâches à exécuter une fois, à l'aide de l'espace de noms des tâches Spring
Avec SpringBoot, nous pouvons exécuter une méthode au démarrage via l'annotation @EventListener
@Component
public class LoadDataOnStartUp
{
@EventListener(ApplicationReadyEvent.class)
public void loadData()
{
// do something
}
}
Publié une autre solution qui implémente WebApplicationInitializer et est appelée bien avant l'instanciation d'un bean printemps, au cas où quelqu'un aurait ce cas d'utilisation
Initialise les paramètres régionaux et le fuseau horaire par défaut avec la configuration Spring
Si vous souhaitez configurer un bean avant que votre application ne soit complètement exécutée, vous pouvez utiliser @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");
}
}
}
Pour un fichier StartupHousekeeper.Java
situé dans le package com.app.startup
,
Faites ceci dans StartupHousekeeper.Java
:
@Component
public class StartupHousekeeper {
@EventListener(ContextRefreshedEvent.class)
public void keepHouse() {
System.out.println("This prints at startup.");
}
}
Et faites ceci dans myDispatcher-servlet.Java
:
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<mvc:annotation-driven />
<context:component-scan base-package="com.app.startup" />
</beans>
Vous pouvez utiliser @EventListener
sur votre composant, qui sera appelé après le démarrage du serveur et l'initialisation de tous les beans.
@EventListener
public void onApplicationEvent(ContextClosedEvent event) {
}