Das in diesem Artikel erstellte Beispielprojekt wurde mit SpringBoot 2.2.1.RELEASE
+ maven 3.5.3
+ idea
entwickelt >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
und es gibt keine spezielle Konfiguration. Erweiterung vor der Containeraktualisierung Klicken Sie auf das Beispiel 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🎜Wenn unser Erweiterungspunkt in einem JAR-Paket platziert wird Wenn externe Dienste bereitgestellt werden, ist dies der Fall Die Verwendung der oben genannten Startregistrierungsmethode ist derzeit offensichtlich nicht möglich. Die empfohlene Methode besteht darin, sich über den SPI-Mechanismus von Spring zu registrieren🎜🎜META-INF/spring.factories
im Ressourcenverzeichnis Datei🎜rrreee🎜Anweisungen🎜AutoConfiguration
wird normalerweise auf diese Weise registriert🎜application .properties
oder application.yml
, konfigurieren Sie Folgendes: 🎜rrreee🎜Test starten🎜🎜Für die oben genannten drei Registrierungsmethoden implementieren wir drei benutzerdefinierte Erweiterungspunkte und nehmen sie dann nach dem Start Schauen Sie sich die tatsächliche Ausgabe an Container " />🎜🎜Die obige Ausgabe kann leicht eine Schlussfolgerung ziehen, die Priorität verschiedener Registrierungsmethoden (um den folgenden Standpunkt vernünftiger zu überprüfen, wird empfohlen, die oben genannten drei benutzerdefinierten Erweiterungen zu ändern und sie aus diesem Grund auszuschließen das durch den Namen verursachte Sortierproblem)🎜@Order
implementieren. Wenn beispielsweise alle oben genannten drei Erweiterungspunkte gestartet werden Bei der Registrierung lautet das Ausgabebeispiel wie folgt: ApplicationContextInitializer vor dem Aktualisieren des SpringBoot-Containers" />🎜🎜Dann kommt der entscheidende Punkt🎜@OrderDie Reihenfolge der Anmerkungsänderung kann die Reihenfolge der <strong>Konfigurationsdatei>-Registrierung</strong> nicht aufheben die Ausführungsreihenfolge und Regeln benutzerdefinierter Implementierungsklassen wie folgt🎜<ul class=" list-paddingleft-2">
<li>🎜Konfigurationsdatei>Startup-Methode🎜</li>
<li>🎜Die gleiche Registrierungsmethode kann Zur Änderung wird die Annotation <code>@Order code> übergeben. Je kleiner der Wert, desto höher die Priorität Schauen Sie sich die Verwendung dieses Erweiterungspunkts an. In welchen Szenarien werden wir ihn verwenden? 🎜🎜Ein häufig vorkommendes Anwendungsszenario besteht darin, die zu aktivierende Konfigurationsdatei anzugeben. 🎜rrreee🎜Aber im Allgemeinen sieht man dies selten, da es ausreicht, die Konfigurationsparameter direkt zu verwenden. Gibt es also welche? Szenarien, in denen dies notwendig ist? 🎜🎜Die Antwort lautet natürlich: Ja. Wenn wir beispielsweise bei der mittlerweile weit verbreiteten Docker-Container-Bereitstellung jedes Mal das gleiche Image erstellen möchten, können wir dann während des tatsächlichen Betriebs entscheiden, welche Konfigurationsdateien im aktuellen Image aktiviert sind Je nach Umgebung ist dies nützlich. Beispielsweise verwenden wir den Umgebungsparameter des Containers <code>app.env
, um die aktuelle laufende Umgebung abzurufen. Wenn es sich um ein Produkt handelt, aktivieren Sie application-. prod.yml
; Wenn es sich um einen Test handelt, aktivieren Sie application-test.yml
🎜🎜Dann können Sie dies jetzt tun🎜rrreee
Das obige ist der detaillierte Inhalt vonSo rufen Sie ApplicationContextInitializer zurück, bevor der SpringBoot-Container aktualisiert wird. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!