Maison >Java >javaDidacticiel >Comment rappeler ApplicationContextInitializer avant l'actualisation du conteneur SpringBoot
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
, 也没有什么特殊的配置
当我们希望实现一个自定义的上下文初始化时,非常简单,实现上面这个接口就行了,如
public class ApplicationContextInitializer01 implements ApplicationContextInitializer { @Override public void initialize(ConfigurableApplicationContext configurableApplicationContext) { System.out.println("ApplicationContextInitializer01"); } }
上面自定义一个扩展点,如何使它生效呢?
官方提供了三种方式,如在启动时,直接进行注册: 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.properties
或 application.yml
中,如下配置
context: initializer: classes: com.git.hui.extention.context.ApplicationContextInitializer03
启动测试
上面三种注册方式,我们实现三个自定义的扩展点,然后启动之后,看一下实际输出
上面的输出,可以简单的得出一个结论,不同注册方式的优先级(为了更合理的验证下面的观点,推荐大家修改下上面三个自定义扩展点名,排除掉是因为扩展名导致的排序问题)
配置文件注册 > SPI注册 > 启动时注册
对于自定义的扩展点实现,当存在顺序关系时,我们可以通过@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)) { } } }
输出实例如下
接着重点来了
若上面的三个自定义实现,不是相同的注册方式,如将03采用配置文件方式进行注册,那么01, 02 依然是启动注册
则顺序是 03 > 02 > 01
即 @Order
注解修饰的顺序,并不能打破 配置文件 > SPI > 启动方式注册的顺序
关于自定义实现类的执行顺序,规则如下
配置文件 > SPI > 启动方式
相同的注册方式,可以通过 @Order
注解进行修饰,值越小则优先级越高
最后我们再来看一下,这个扩展点到底有什么用,我们再什么场景下会用到这个呢?
一个经常可以看到的应用场景如通过它来指定需要激活的配置文件
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
application .yml
, et il n'y a pas de configuration spéciale#🎜🎜##🎜🎜#II Instance de point d'extension avant l'actualisation du conteneur#🎜🎜#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); } } }
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#🎜🎜#AutoConfiguration
est généralement enregistrée de cette manière#🎜🎜# li>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#🎜🎜##🎜🎜##🎜🎜##🎜🎜#Le point suivant est了#🎜🎜#@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#🎜🎜#@Order
Plus la valeur est petite, plus la priorité est élevée #🎜🎜#<.> ul>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!