Maison  >  Article  >  Java  >  Comment implémenter la surveillance des événements de démarrage du service d'application Springboot

Comment implémenter la surveillance des événements de démarrage du service d'application Springboot

WBOY
WBOYavant
2023-05-16 23:10:372128parcourir

    1. Introduction

    Spring Boot fournit deux interfaces : CommandLineRunner et ApplicationRunner, qui sont utilisées pour effectuer un traitement spécial lors du démarrage de l'application. Ces codes seront exécutés avant que la méthode run() de SpringApplication ne soit terminée. Par rapport à l'écouteur personnalisé de l'interface ApplicationListener de Spring et à l'écouteur ServletContextListener de Servlet présentés dans le chapitre précédent. L'avantage d'utiliser les deux est que vous pouvez facilement utiliser les paramètres de démarrage de l'application et effectuer différentes opérations d'initialisation en fonction de différents paramètres.

    2. Introduction aux scénarios courants

    Implémentez les interfaces CommandLineRunner et ApplicationRunner. Habituellement utilisé pour l'exécution de code spécial avant le démarrage de l'application, tel que :

    • Chargement des données système couramment utilisées en mémoire

    • Nettoyage des données indésirables de la dernière exécution de l'application

    • Envoi de notifications après le démarrage du système avec succès, etc.

    J'ai implémenté l'interface CommandLineRunner et chargé les données de configuration couramment utilisées dans le système au démarrage de l'application, comme le montre la figure ci-dessous. Chargez les données de la base de données dans la mémoire Lorsque vous utiliserez les données ultérieurement, il vous suffit d'appeler la méthode getSysConfigList. Il n'est pas nécessaire de charger les données dans la base de données à chaque fois. Économisez les ressources système et réduisez le temps de chargement des données.

    Comment implémenter la surveillance des événements de démarrage du service dapplication Springboot

    2. Une petite expérience de code est implémentée via la définition de @Component

    CommandLineRunner : le paramètre est un tableau de chaînes

    @Slf4j
    @Component
    public class CommandLineStartupRunner implements CommandLineRunner {
        @Override
        public void run(String... args){
            log.info("CommandLineRunner传入参数:{}", Arrays.toString(args));
        }
    }

    ApplicationRunner : les paramètres sont placés dans ApplicationArguments et les paramètres sont obtenus via getOptionNames(), getOptionValues( ), et getSourceArgs()

    @Slf4j
    @Component
    public class AppStartupRunner implements ApplicationRunner {
        @Override
        public void run(ApplicationArguments args)  {
            log.info("ApplicationRunner参数名称: {}", args.getOptionNames());
            log.info("ApplicationRunner参数值: {}", args.getOptionValues("age"));
            log.info("ApplicationRunner参数: {}", Arrays.toString(args.getSourceArgs()));
        }
    }

    Obtenu via la méthode de définition @Bean

    Cette méthode peut spécifier l'ordre d'exécution. Notez que les deux premiers Beans sont CommandLineRunner et le dernier Bean est ApplicationRunner.

    @Configuration
    public class BeanRunner {
        @Bean
        @Order(1)
        public CommandLineRunner runner1(){
            return new CommandLineRunner() {
                @Override
                public void run(String... args){
                    System.out.println("BeanCommandLineRunner run1()" + Arrays.toString(args));
                }
            };
        }
    
        @Bean
        @Order(2)
        public CommandLineRunner runner2(){
            return new CommandLineRunner() {
                @Override
                public void run(String... args){
                    System.out.println("BeanCommandLineRunner run2()" + Arrays.toString(args));
                }
            };
        }
    
        @Bean
        @Order(3)
        public ApplicationRunner runner3(){
            return new ApplicationRunner() {
                @Override
                public void run(ApplicationArguments args){
                    System.out.println("BeanApplicationRunner run3()" + Arrays.toString(args.getSourceArgs()));
                }
            };
        }
    }

    Vous pouvez définir l'ordre d'exécution via @Order

    3. Exécutez le test

    Ajoutez les paramètres suivants à la configuration de démarrage d'IDEA Springboot, enregistrez et démarrez l'application

    Comment implémenter la surveillance des événements de démarrage du service dapplication Springboot

    Résultat de sortie du test :

    c.z. boot.launch.config .AppStartupRunner : nom du paramètre ApplicationRunner : [nom, âge]
    c.z.boot.launch.config.AppStartupRunner : valeur du paramètre ApplicationRunner : [18]
    c.z.boot.launch.config.AppStartupRunner : paramètre ApplicationRunner : [-- name=zimug, - -age=18]

    BeanApplicationRunner run3()[--name=zimug, --age=18]

    c.z.b.l.config.CommandLineStartupRunner : Paramètres entrants de CommandLineRunner : [--name=zimug, --age =18]
    BeanCommandLineRunner run1()[--name=zimug, --age=18]
    e=18]
    BeanCommandLineRunner run2()[--name=zimug, --age=18]

    Après de nombreux tests , l'auteur a découvert que dans les résultats des tests, cet ordre de priorité a toujours été comme ceci, mais il n'est actuellement pas clair si c'est la norme

    • La priorité d'exécution d'ApplicationRunner est supérieure à celle de CommandLineRunner

    • La priorité de Runner s'exécutant dans la forme du Bean est inférieure à l'annotation du composant. La manière d'implémenter l'interface Runner

    • L'annotation d'ordre ne peut garantir que l'ordre d'exécution du même CommandLineRunner ou ApplicationRunner, et ne peut pas garantir l'ordre entre les classes

    Résumé

    4.

    L'utilisation principale de CommandLineRunner et d'ApplicationRunner est cohérente, c'est-à-dire qu'ils sont utilisés pour l'exécution de code spécial avant le démarrage de l'application. L'ordre d'exécution d'ApplicationRunner précède CommandLineRunner ; ApplicationRunner encapsule les paramètres dans des objets et fournit des méthodes pour obtenir les noms de paramètres, les valeurs de paramètres, etc., ce qui rend l'opération plus pratique.

    5. Résumé du problème

    C'est un vrai problème que l'auteur a rencontré dans la pratique, c'est-à-dire que j'ai défini plusieurs implémentations de CommandLineRunner. Un problème étrange se pose : Lorsque vous définissez plusieurs implémentations de CommandLineRunner, une ou plusieurs d'entre elles ne s'exécuteront pas.

    Analyse : Le code suivant est le code que SpringBootApplication exécutera après le démarrage du projet. Vous pouvez voir que CommandLineRunner ou ApplicationRunner est démarré via un parcours dans le code. En d'autres termes, le CommandLineRunner suivant ne sera exécuté qu'une fois l'exécution du CommandLineRunner précédent terminée, qui est exécutée de manière synchrone.

    private void callRunners(ApplicationContext context, ApplicationArguments args) {
    		List<Object> runners = new ArrayList<>();
    		runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
    		runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
    		AnnotationAwareOrderComparator.sort(runners);
    		for (Object runner : new LinkedHashSet<>(runners)) {
    			if (runner instanceof ApplicationRunner) {
    				callRunner((ApplicationRunner) runner, args);
    			}
    			if (runner instanceof CommandLineRunner) {
    				callRunner((CommandLineRunner) runner, args);
    			}
    		}
    	}

    Ainsi, si une API de blocage synchrone ou une boucle while(true) est appelée dans le corps de la méthode d'exécution d'une implémentation de CommandLineRunner, les autres implémentations après CommandLineRunner dans la traversée ne seront pas exécutées.

    Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

    Déclaration:
    Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer