Exécution des données d’installation au démarrage au printemps

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.

Read more

Spring Boot: Configuration d'une classe principale

Apprenez à configurer la classe principale de votre application Spring Boot dans Maven et Gradle.

Read more

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:

  1. Le constructeur

  2. les méthodes annotées@PostConstruct

  3. la méthodeafterPropertiesSet() de InitializingBean

  4. 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.