Heim  >  Artikel  >  Java  >  So rufen Sie ApplicationContextInitializer zurück, bevor der SpringBoot-Container aktualisiert wird

So rufen Sie ApplicationContextInitializer zurück, bevor der SpringBoot-Container aktualisiert wird

WBOY
WBOYnach vorne
2023-05-11 08:58:111001Durchsuche

I. Projektvorbereitung

Das in diesem Artikel erstellte Beispielprojekt wurde mit SpringBoot 2.2.1.RELEASE + maven 3.5.3 + ideaentwickelt >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

启动测试

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

So rufen Sie ApplicationContextInitializer zurück, bevor der SpringBoot-Container aktualisiert wird

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

  • 配置文件注册 > 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)) {
        }
    }
}

输出实例如下

So rufen Sie ApplicationContextInitializer zurück, bevor der SpringBoot-Container aktualisiert wird

接着重点来了

  • 若上面的三个自定义实现,不是相同的注册方式,如将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

Ich werde nicht näher auf die spezifische SpringBoot-Projekterstellung eingehen. Die Kern-POM-Datei erfordert keine zusätzlichen Abhängigkeiten. Die Konfigurationsdatei application.yml und es gibt keine spezielle Konfiguration. Erweiterung vor der Containeraktualisierung Klicken Sie auf das Beispiel

1. Benutzerdefinierter ApplicationContextInitializer

Wenn wir eine benutzerdefinierte Kontextinitialisierung implementieren möchten, ist es sehr einfach, einfach die obige Schnittstelle zu implementieren, z. B. 🎜
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 . Erweiterungspunktregistrierung🎜Wie kann ich einen Erweiterungspunkt oben anpassen und wirksam machen? 🎜🎜Offiziell bietet es drei Möglichkeiten, z. B. die direkte Registrierung beim Start: 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.factoriesim Ressourcenverzeichnis Datei🎜rrreee🎜Anweisungen🎜
  • 🎜Der obige SPI-Mechanismus wird jedem dringend empfohlen. Im vorherigen Artikel AutoConfiguration wird normalerweise auf diese Weise registriert🎜
🎜Zusätzlich zu den beiden oben genannten Registrierungsmethoden gibt es auch eine Konfigurationsdateimethode in der Konfigurationsdatei 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)🎜
  • 🎜Registrierung der Konfigurationsdatei> Registrierung beim Start🎜

3 Sequenzspezifikation

🎜Wenn bei der Implementierung eines benutzerdefinierten Erweiterungspunkts eine Sequenzbeziehung besteht, können wir diese über die Annotation @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🎜
  • 🎜Wenn die oben genannten drei benutzerdefinierten Implementierungen nicht identisch sind Registrierungsmethode, z. B. 03. Wenn Sie die Konfigurationsdateimethode zur Registrierung verwenden, beginnen 01 und 02 weiterhin mit der Registrierung🎜
  • 🎜Die Reihenfolge ist 03 > 01🎜
  • 🎜Das heißt, @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!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen