Home  >  Article  >  Java  >  How to call back ApplicationContextInitializer before SpringBoot container refreshes

How to call back ApplicationContextInitializer before SpringBoot container refreshes

WBOY
WBOYforward
2023-05-11 08:58:11922browse

I. Project preparation

The example project created in this article is developed using SpringBoot 2.2.1.RELEASE maven 3.5.3 idea

I won’t go into details about the specific SpringBoot project creation. The core pom file does not require additional dependencies.

Configuration file application.yml, and there is no special configuration.

II. Extension point instance before container refresh

1. Custom ApplicationContextInitializer

When we want to implement a custom context initialization, it is very simple, implement the above interface That’s it, like

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

2. Extension point registration

Customize an extension point above, how to make it effective?

The official provides three ways, such as registering directly at startup: 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)) {
        }
    }
}

When our extension point When it is provided to the outside world in a jar package, it is obviously not feasible to use the above startup registration method. At this time, the more recommended method is to register through Spring's SPI mechanism

## in the resource directory #META-INF/spring.factoriesRegister in the file

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

Instructions

  • The above SPI mechanism is highly recommended for everyone to use. In previous articles,

    AutoConfiguration is usually registered in this way

In addition to the above two registration methods, there is also a configuration file Method, in the configuration file

application.properties or application.yml, configure the following

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

Start the test

above For the three registration methods, we implement three customized extension points, and then after starting, look at the actual output

How to call back ApplicationContextInitializer before SpringBoot container refreshes

The above output can simply draw a conclusion, Priority of different registration methods (in order to more reasonably verify the following point of view, it is recommended that you modify the above three custom extensions to eliminate the sorting problem caused by the extension)

  • Configuration file registration> SPI registration> Registration at startup

3. Execution order specification

For custom extension point implementation, when there is a sequence relationship, We can achieve this through the

@Order annotation. For example, when the above three extension points are all registered through the startup method,

@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)) {
        }
    }
}

The output example is as follows

How to call back ApplicationContextInitializer before SpringBoot container refreshes

Then the key point comes

  • If the above three custom implementations are not the same registration method, for example, use the configuration file method for 03 Registration, then 01, 02 still starts the registration

  • , then the order is 03 > 02 > 01

  • that is,

    @Order The order of annotation modification cannot break the order of Configuration File> SPI > Startup Mode Registration

About the execution order of custom implementation classes, The rules are as follows

  • Configuration File> SPI> Startup method

  • The same registration method can be passed

    @Order Annotations are used for modification. The smaller the value, the higher the priority.

4. Usage scenario examples

Finally, let’s take a look at what the use of this extension point is. In what scenarios would this be used?

A common application scenario is to use it to specify the configuration file that needs to be activated

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

But generally it is rare to see anyone doing this, because just use the configuration parameters directly. So is there any scenario that requires this?

The answer is of course yes. For example, in the now widely popular docker container deployment, when we want to use the same image every time, and then during actual operation, we can determine the current image according to different environments. Which configuration files are enabled will be useful at this time

For example, we use the container's environment parameters

app.env to obtain the current running environment. If it is prod, activateapplication- prod.yml; If it is test, activate application-test.yml

Then you can do this at this time

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);
        }
    }
}

The above is the detailed content of How to call back ApplicationContextInitializer before SpringBoot container refreshes. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:yisu.com. If there is any infringement, please contact admin@php.cn delete