Exécution des données d'installation au démarrage au printemps
1. introduction
Dans cet article, nous allons nous concentrer sur la façon de fairerun logic at the startup of a Spring application.
Lectures complémentaires:
Configurer une application Web Spring Boot
Certaines des configurations les plus utiles pour une application Spring Boot.
Spring Boot: Configuration d'une classe principale
Apprenez à configurer la classe principale de votre application Spring Boot dans Maven et Gradle.
2. Exécution de Logic au démarrage
L'exécution de la logique pendant / après le démarrage de l'application Spring est un scénario courant, mais qui pose plusieurs problèmes.
Afin de bénéficier de l’inverse de contrôle, nous devons naturellement renoncer au contrôle partiel du flux de l’application vers le conteneur - c’est pourquoi l’instanciation, la logique de configuration au démarrage, etc. nécessitent une attention particulière.
Nous ne pouvons pas simplement inclure notre logique dans les constructeurs des beans ou appeler des méthodes après instanciation d'un objet; nous ne contrôlons tout simplement pas ces processus.
Regardons l'exemple réel:
@Component
public class InvalidInitExampleBean {
@Autowired
private Environment env;
public InvalidInitExampleBean() {
env.getActiveProfiles();
}
}
Ici, nous essayons d'accéder à un champautowired dans le constructeur. Lorsque le constructeur est appelé, le bean Spring n'est pas encore complètement initialisé. Ceci est problématique carcalling not yet initialized fields will of course result in NullPointerExceptions.
Le printemps nous donne quelques moyens de gérer cette situation.
2.1. L'annotation@PostConstruct
L'annotation@PostConstruct de Javax peut être utilisée pour annoter une méthode qui doit être exécutéeonce immediately after the bean’s initialization. Gardez à l'esprit que la méthode annotée sera exécutée par Spring même s'il n'y a rien à injecter.
Voici@PostConstruct en action:
@Component
public class PostConstructExampleBean {
private static final Logger LOG
= Logger.getLogger(PostConstructExampleBean.class);
@Autowired
private Environment environment;
@PostConstruct
public void init() {
LOG.info(Arrays.asList(environment.getDefaultProfiles()));
}
}
Dans l'exemple ci-dessus, vous pouvez voir que l'instanceEnvironment a été injectée en toute sécurité, puis appelée dans la méthode annotée@PostConstruct sans lancer unNullPointerException.
2.2. L'interfaceInitializingBean
L'approcheInitializingBean fonctionne à peu près de la même manière que la précédente. Au lieu d'annoter une méthode, vous devez implémenter l'interfaceInitializingBean et la méthodeafterPropertiesSet().
Ici vous pouvez voir l'exemple précédent implémenté à l'aide de l'interfaceInitializingBean:
@Component
public class InitializingBeanExampleBean implements InitializingBean {
private static final Logger LOG
= Logger.getLogger(InitializingBeanExampleBean.class);
@Autowired
private Environment environment;
@Override
public void afterPropertiesSet() throws Exception {
LOG.info(Arrays.asList(environment.getDefaultProfiles()));
}
}
2.3. UnApplicationListener
Cette approche peut être utilisée pourrunning logic after the Spring context has been initialized, donc nous ne nous concentrons pas sur un bean en particulier, mais attendons qu'ils s'initialisent tous.
Pour ce faire, vous devez créer un bean qui implémente l'interfaceApplicationListener<ContextRefreshedEvent>:
@Component
public class StartupApplicationListenerExample implements
ApplicationListener {
private static final Logger LOG
= Logger.getLogger(StartupApplicationListenerExample.class);
public static int counter;
@Override public void onApplicationEvent(ContextRefreshedEvent event) {
LOG.info("Increment counter");
counter++;
}
}
Les mêmes résultats peuvent être obtenus en utilisant l'annotation@EventListener nouvellement introduite:
@Component
public class EventListenerExampleBean {
private static final Logger LOG
= Logger.getLogger(EventListenerExampleBean.class);
public static int counter;
@EventListener
public void onApplicationEvent(ContextRefreshedEvent event) {
LOG.info("Increment counter");
counter++;
}
}
Dans cet exemple, nous avons choisi lesContextRefreshedEvent. Assurez-vous de choisir un événement approprié qui correspond à vos besoins.
2.4. L'attribut Initmethod@Bean
La propriété initMethod peut être utilisée pour exécuter une méthode après l’initialisation d’un bean.
Voici à quoi ressemble un haricot:
public class InitMethodExampleBean {
private static final Logger LOG = Logger.getLogger(InitMethodExampleBean.class);
@Autowired
private Environment environment;
public void init() {
LOG.info(Arrays.asList(environment.getDefaultProfiles()));
}
}
Vous pouvez remarquer qu’aucune interface spéciale n’est implémentée ni aucune annotation spéciale utilisée.
Ensuite, nous pouvons définir le bean en utilisant l'annotation@Bean:
@Bean(initMethod="init")
public InitMethodExampleBean exBean() {
return new InitMethodExampleBean();
}
Et voici à quoi ressemble une définition de bean dans une configuration XML:
2.5. Injection de constructeur
Si vous injectez des champs à l'aide de l'injection de constructeur, vous pouvez simplement inclure votre logique dans un constructeur:
@Component
public class LogicInConstructorExampleBean {
private static final Logger LOG
= Logger.getLogger(LogicInConstructorExampleBean.class);
private final Environment environment;
@Autowired
public LogicInConstructorExampleBean(Environment environment) {
this.environment = environment;
LOG.info(Arrays.asList(environment.getDefaultProfiles()));
}
}
2.6. Botte de printempsCommandLineRunner
Spring boot fournit une interfaceCommanLineRunner avec une méthode de rappelrun() qui peut être appelée au démarrage de l'application après l'instanciation du contexte de l'application Spring.
Regardons un exemple:
@Component
public class CommandLineAppStartupRunner implements CommandLineRunner {
private static final Logger LOG =
LoggerFactory.getLogger(CommandLineAppStartupRunner.class);
public static int counter;
@Override
public void run(String...args) throws Exception {
LOG.info("Increment counter");
counter++;
}
}
Le code source complet peut être trouvé surGithub.
Note: Comme mentionné dans lesdocumentation, plusieurs beansCommandLineRunner peuvent être définis dans le même contexte d'application et peuvent être commandés à l'aide de l'interface@Ordered ou de l'annotation@Order .
2.7. Botte de printempsApplicationRunner
Similaire àCommandLineRunner, Spring boot fournit également une interfaceApplicationRunner avec une méthoderun() à appeler au démarrage de l'application. Cependant, au lieu des argumentsStringbruts passés à la méthode de rappel, nous avons une instance de la classeApplicationArguments.
L'interfaceApplicationArguments a des méthodes pour obtenir des valeurs d'argument qui sont des options et des valeurs d'argument simples. Un argument préfixé par - - est un argument d'option.
Regardons un exemple:
@Component
public class AppStartupRunner implements ApplicationRunner {
private static final Logger LOG =
LoggerFactory.getLogger(AppStartupRunner.class);
public static int counter;
@Override
public void run(ApplicationArguments args) throws Exception {
LOG.info("Application started with option names : {}",
args.getOptionNames());
LOG.info("Increment counter");
counter++;
}
}
Le code source complet peut être trouvé surGithub.
3. Combinaison de mécanismes
Pour obtenir un contrôle total sur vos haricots, vous pouvez combiner les mécanismes ci-dessus.
L'ordre d'exécution est le suivant:
-
Le constructeur
-
les méthodes annotées@PostConstruct
-
la méthodeafterPropertiesSet() de InitializingBean
-
la méthode d'initialisation spécifiée commeinit-method dans XML
Créons un Spring bean qui combine tous les mécanismes:
@Component
@Scope(value = "prototype")
public class AllStrategiesExampleBean implements InitializingBean {
private static final Logger LOG
= Logger.getLogger(AllStrategiesExampleBean.class);
public AllStrategiesExampleBean() {
LOG.info("Constructor");
}
@Override
public void afterPropertiesSet() throws Exception {
LOG.info("InitializingBean");
}
@PostConstruct
public void postConstruct() {
LOG.info("PostConstruct");
}
public void init() {
LOG.info("init-method");
}
}
Si vous essayez d'instancier ce bean, vous pourrez voir les journaux qui correspondent à l'ordre spécifié ci-dessus:
[main] INFO o.b.startup.AllStrategiesExampleBean - Constructor
[main] INFO o.b.startup.AllStrategiesExampleBean - PostConstruct
[main] INFO o.b.startup.AllStrategiesExampleBean - InitializingBean
[main] INFO o.b.startup.AllStrategiesExampleBean - init-method
4. Conclusion
Dans cet article, nous avons illustré plusieurs façons d'exécuter la logique au démarrage de l'application Spring.
Des exemples de code peuvent être trouvés surGitHub.