Maison  >  Article  >  Java  >  Comment rappeler ApplicationContextInitializer avant l'actualisation du conteneur SpringBoot

Comment rappeler ApplicationContextInitializer avant l'actualisation du conteneur SpringBoot

WBOY
WBOYavant
2023-05-11 08:58:111001parcourir

I. Préparation du projet

L'exemple de projet créé dans cet article utilise SpringBoot 2.2.1.RELEASE + maven 3.5.3 + idée pour le développement SpringBoot 2.2.1.RELEASE + maven 3.5.3 + idea进行开发

具体的SpringBoot项目工程创建就不赘述了,核心的pom文件,无需额外的依赖

配置文件 application.yml, 也没有什么特殊的配置

II. 容器刷新前扩展点实例

1. 自定义ApplicationContextInitializer

当我们希望实现一个自定义的上下文初始化时,非常简单,实现上面这个接口就行了,如

public class ApplicationContextInitializer01 implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        System.out.println("ApplicationContextInitializer01");
    }
}

2. 扩展点注册

上面自定义一个扩展点,如何使它生效呢?

官方提供了三种方式,如在启动时,直接进行注册: springApplication.addInitializers(new ApplicationContextInitializer01());

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication springApplication = new SpringApplication(Application.class);
        springApplication.addInitializers(new ApplicationContextInitializer01());
        try (ConfigurableApplicationContext context = springApplication.run(args)) {
        }
    }
}

当我们的扩展点是放在一个jar包中对外提供时,使用上面的启动注册方式显然是不可行的,此时更推荐的做法就是通过Spring的SPI机制进行注册

在资源目录下的META-INF/spring.factories文件中进行注册

org.springframework.context.ApplicationContextInitializer=com.git.hui.extention.context.ApplicationContextInitializer02

说明

  • 上面SPI的机制非常推荐大家使用,在之前的文章中,AutoConfiguration的注册通常也是使用这种方式

除了上面的两种注册方式之外,另外还有一个配置文件的方式,在配置文件application.propertiesapplication.yml中,如下配置

context:
  initializer:
    classes: com.git.hui.extention.context.ApplicationContextInitializer03

启动测试

上面三种注册方式,我们实现三个自定义的扩展点,然后启动之后,看一下实际输出

Comment rappeler ApplicationContextInitializer avant lactualisation du conteneur SpringBoot

上面的输出,可以简单的得出一个结论,不同注册方式的优先级(为了更合理的验证下面的观点,推荐大家修改下上面三个自定义扩展点名,排除掉是因为扩展名导致的排序问题)

  • 配置文件注册 > SPI注册 > 启动时注册

3. 执行顺序指定

对于自定义的扩展点实现,当存在顺序关系时,我们可以通过@Order注解来实现, 如当上面的三个扩展点都是通过启动方式注册时

@Order(5)
public class ApplicationContextInitializer01 implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        System.out.println("ApplicationContextInitializer01");
    }
}

@Order(2)
public class ApplicationContextInitializer02 implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        System.out.println("ApplicationContextInitializer02");
    }
}

@Order(10)
public class ApplicationContextInitializer03 implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        System.out.println("ApplicationContextInitializer03");
    }
}

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication springApplication = new SpringApplication(Application.class);
        springApplication.addInitializers(new ApplicationContextInitializer01(), new ApplicationContextInitializer02(), new ApplicationContextInitializer03());
        try (ConfigurableApplicationContext context = springApplication.run(args)) {
        }
    }
}

输出实例如下

Comment rappeler ApplicationContextInitializer avant lactualisation du conteneur SpringBoot

接着重点来了

  • 若上面的三个自定义实现,不是相同的注册方式,如将03采用配置文件方式进行注册,那么01, 02 依然是启动注册

  • 则顺序是 03 > 02 > 01

  • @Order注解修饰的顺序,并不能打破 配置文件 > SPI > 启动方式注册的顺序

关于自定义实现类的执行顺序,规则如下

  • 配置文件 > SPI > 启动方式

  • 相同的注册方式,可以通过 @Order 注解进行修饰,值越小则优先级越高

4. 使用场景示例

最后我们再来看一下,这个扩展点到底有什么用,我们再什么场景下会用到这个呢?

一个经常可以看到的应用场景如通过它来指定需要激活的配置文件

public class ApplicationContextInitializer03 implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        // 指定激活prod对应的配置文件
        configurableApplicationContext.getEnvironment().setActiveProfiles("prod");
    }
}

但是一般也很少见到有人这么干,因为直接使用配置参数就行了,那么有场景需要这么做么?

答案当然是有的,比如现在广为流行的docker容器部署,当我们希望每次都是打同一个镜像,然后在实际运行的时候,根据不同的环境来决定当前镜像到底启用哪些配置文件,这时就有用了

比如我们通过容器的环境参数 app.env 来获取当前运行的环境,如果是prod,则激活application-prod.yml; 如果是test,则激活application-test.yml

Je n'entrerai pas dans les détails sur la création spécifique du projet SpringBoot Le fichier pom principal ne nécessite aucune dépendance supplémentaire

Fichier de configuration. application .yml, et il n'y a pas de configuration spéciale#🎜🎜##🎜🎜#II Instance de point d'extension avant l'actualisation du conteneur#🎜🎜#

1 Personnaliser ApplicationContextInitializer

#🎜. 🎜#Quand Lorsque nous voulons implémenter une initialisation de contexte personnalisée, c'est très simple. Il suffit d'implémenter l'interface ci-dessus, telle que #🎜🎜#
public class EenvActiveApplicationContextInitializer implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        String env = System.getenv("app.env");
        if ("prod".equalsIgnoreCase(env)) {
            configurableApplicationContext.getEnvironment().setActiveProfiles("prod");
        } else if ("test".equalsIgnoreCase(env)) {
            configurableApplicationContext.getEnvironment().setActiveProfiles("test");
        } else {
            throw new RuntimeException("非法的环境参数:" + env);
        }
    }
}

2 Enregistrement du point d'extension

#🎜🎜# Personnaliser une extension. point ci-dessus, Comment le rendre efficace ? #🎜🎜##🎜🎜# Fournit officiellement trois méthodes, comme l'enregistrement directement au démarrage : springApplication.addInitializers(new ApplicationContextInitializer01());#🎜🎜#rrreee#🎜🎜# Lorsque nos points d'extension sont fournis en externe dans un package jar, il n'est évidemment pas possible d'utiliser la méthode d'enregistrement de démarrage ci-dessus. Pour le moment, la méthode la plus recommandée consiste à s'inscrire via le mécanisme SPI de Spring#🎜🎜##🎜🎜# Inscrivez-vous dans le . Fichier META-INF/spring.factories dans le répertoire des ressources#🎜🎜#rrreee#🎜🎜#Instructions#🎜🎜#
    #🎜🎜#Le mécanisme SPI ci-dessus est fortement recommandé à tout le monde. Dans les articles précédents, la AutoConfiguration est généralement enregistrée de cette manière#🎜🎜# li>
#🎜 🎜#En plus des deux méthodes d'enregistrement ci-dessus, il existe également une méthode de fichier de configuration, dans le fichier de configuration application.properties ou application.yml, configurez ce qui suit #🎜 🎜#rrreee#🎜🎜#<strong>Démarrer le test</strong>#🎜🎜##🎜🎜#Pour les trois méthodes d'enregistrement ci-dessus, nous implémentons trois points d'extension personnalisés, puis après avoir démarré, jetez un œil au résultat réel #🎜🎜##🎜🎜#<img src="https://img.php.cn/upload/article/000/887/227/168376669459095.png" alt="Actualisation du conteneur SpringBoot Comment rappeler ApplicationContextInitializer">#🎜🎜##🎜🎜#Le résultat ci-dessus peut simplement tirer une conclusion, la priorité des différentes méthodes d'enregistrement (afin de vérifier plus raisonnablement les points suivants, il est recommandé de modifier les trois ci-dessus Personnaliser le nom de l'extension pour éliminer problèmes de tri causés par les extensions) #🎜🎜#<ul class=" list-paddingleft-2"><li>#🎜🎜#Enregistrement du fichier de configuration> Inscription SPI> ><h4>3. Spécification de l'ordre d'exécution</h4>#🎜🎜#Pour l'implémentation d'un point d'extension personnalisé, lorsqu'il existe une relation séquentielle, nous pouvons transmettre l'annotation <code>@ Order par exemple. les trois points d'extension ci-dessus sont enregistrés via la méthode de démarrage#🎜🎜#rrreee#🎜🎜#L'exemple de sortie est le suivant#🎜🎜##🎜🎜#Comment rappeler ApplicationContextInitializer avant que le conteneur SpringBoot ne soit actualisé#🎜🎜##🎜🎜#Le point suivant est了#🎜🎜#
  • #🎜🎜#Si les trois implémentations personnalisées ci-dessus ne sont pas la même méthode d'enregistrement, par exemple, utilisez la méthode du fichier de configuration pour 03 Pour vous inscrire, puis 01, 02 est toujours le début des inscriptions #🎜🎜#
  • #🎜🎜#, puis la commande est 03> 🎜 #C'est-à-dire que l'ordre de modification de l'annotation @Order ne peut pas rompre l'ordre du Fichier de configuration> SPI > ul> #🎜🎜#À propos de l'ordre d'exécution des classes d'implémentation personnalisées, les règles sont les suivantes#🎜🎜#
    • #🎜🎜#Fichier de configuration> method#🎜🎜 #
    • #🎜🎜#La même méthode d'enregistrement peut être modifiée via l'annotation @Order Plus la valeur est petite, plus la priorité est élevée #🎜🎜#<.> ul>

      4. Exemples de scénarios d'utilisation

      #🎜🎜#Enfin, regardons à quoi sert ce point d'extension, et dans quels scénarios allons-nous l'utiliser ? #🎜🎜##🎜🎜#Un scénario d'application courant consiste à l'utiliser pour spécifier le fichier de configuration qui doit être activé#🎜🎜#rrreee#🎜🎜#Mais en général, il est rare de voir quelqu'un faire cela, car la configuration est utilisé directement Les paramètres suffisent, mais existe-t-il des scénarios où cela est nécessaire ? #🎜🎜##🎜🎜# Bien sûr, il existe une réponse. Par exemple, avec le désormais très populaire déploiement de conteneur Docker, lorsque nous voulons imprimer la même image à chaque fois, puis décider de l'image actuelle en fonction des différents environnements. est réellement exécuté, quels fichiers de configuration sont activés par l'image seront utiles à ce moment #🎜🎜##🎜🎜#Par exemple, nous utilisons le paramètre d'environnement du conteneur app.env pour obtenir le environnement d'exécution actuel. S'il s'agit d'un prod, activez-le application-prod.yml. S'il s'agit d'un test, activez application-test.yml#🎜🎜##🎜🎜# ; Ensuite, vous pouvez le faire à ce moment-là#🎜🎜#rrreee

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