>  기사  >  Java  >  SpringBoot 컨테이너가 새로 고쳐지기 전에 ApplicationContextInitializer를 다시 호출하는 방법

SpringBoot 컨테이너가 새로 고쳐지기 전에 ApplicationContextInitializer를 다시 호출하는 방법

WBOY
WBOY앞으로
2023-05-11 08:58:111001검색

I. 프로젝트 준비

이 기사에서 만든 예제 프로젝트는 SpringBoot 2.2.1.RELEASE + maven 3.5.3 + idea를 사용하여 개발되었습니다. >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

启动测试

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

SpringBoot 컨테이너가 새로 고쳐지기 전에 ApplicationContextInitializer를 다시 호출하는 방법

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

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

输出实例如下

SpringBoot 컨테이너가 새로 고쳐지기 전에 ApplicationContextInitializer를 다시 호출하는 방법

接着重点来了

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

특정 SpringBoot 프로젝트 생성에 대해서는 자세히 설명하지 않겠습니다. 핵심 pom 파일에는 추가 종속성이 필요하지 않습니다

구성 파일 application.yml이 있으며 특별한 구성도 없습니다🎜🎜II. 컨테이너 새로 고침 전 확장 예시 🎜

1. Custom ApplicationContextInitializer

🎜를 클릭하세요. 사용자 정의 컨텍스트 초기화를 구현하려면 매우 간단합니다. 🎜
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와 같이 위의 인터페이스를 구현하면 됩니다. . 확장점 등록🎜위의 확장점을 어떻게 사용자 정의하고, 어떻게 적용하나요? 🎜🎜시작 시 직접 등록하는 등 세 가지 방법을 공식적으로 제공합니다. springApplication.addInitializers(new ApplicationContextInitializer01());🎜rrreee🎜 확장 포인트가 jar 패키지에 배치될 때 외부 서비스를 제공할 때 위의 시작 등록 방법을 사용하는 것은 분명히 불가능합니다. 이때 더 권장되는 방법은 Spring의 SPI 메커니즘🎜🎜META-INF/spring.factories를 통해 리소스 디렉터리에 등록하는 것입니다. file🎜rrreee🎜지침🎜
  • 🎜위의 SPI 메커니즘은 이전 기사에서 AutoConfiguration을 사용하는 것이 좋습니다. 는 일반적으로 이런 방식으로 등록됩니다🎜
🎜위의 두 가지 등록 방법 외에도 구성 파일 application.properties에 구성 파일 방법도 있습니다. > 또는 application.yml, 다음을 구성합니다. 🎜rrreee🎜테스트 시작🎜🎜위의 세 가지 등록 방법에 대해 세 가지 맞춤형 확장 포인트를 구현하고 시작한 후 실제 출력 살펴보기🎜🎜SpringBoot를 새로 고치기 전에 ApplicationContextInitializer를 다시 호출하는 방법 컨테이너 🎜🎜위 출력은 다양한 등록 방법의 우선순위라는 결론을 쉽게 도출할 수 있습니다(다음 관점을 보다 합리적으로 확인하려면 위의 세 가지 사용자 정의 확장을 수정하고 제외하는 것이 좋습니다. 이름으로 인한 확장자 정렬 문제)🎜
  • 🎜구성 파일 등록> 시작 시 등록🎜

3. 시퀀스 사양

🎜사용자 정의 확장 포인트 구현의 경우 시퀀스 관계가 있는 경우 @Order 주석을 통해 구현할 수 있습니다. 예를 들어 위의 세 확장 포인트가 모두 다음을 통해 시작되는 경우입니다. 🎜rrreee🎜등록시 출력 예시는 다음과 같습니다🎜🎜콜백 방법 SpringBoot 컨테이너를 새로 고치기 전 ApplicationContextInitializer🎜🎜그러면 핵심이 나옵니다🎜
  • 🎜위의 세 가지 사용자 정의 구현이 동일하지 않은 경우 03과 같은 등록 방법 구성 파일 방법을 사용하여 등록하면 01과 02가 계속 등록을 시작합니다🎜
  • 🎜순서는 03 > 02 > 🎜즉, @Order주석 수정 순서는 구성 파일> 시작 모드 등록🎜
🎜의 순서를 깨뜨릴 수 없습니다. 사용자 정의 구현 클래스의 실행 순서 및 규칙은 다음과 같습니다🎜
  • 🎜Configuration file> SPI >up method🎜
  • 🎜동일한 등록 방법은 다음과 같습니다. 수정을 위해 @Order code> 주석을 전달합니다. 값이 작을수록 우선순위가 높아집니다🎜

4. 사용 시나리오 예

🎜마지막으로 살펴보겠습니다. 이 확장 포인트의 용도가 무엇인지 살펴보겠습니다. 어떤 시나리오에서 이것을 사용할 것입니까? 🎜🎜일반적으로 볼 수 있는 응용 프로그램 시나리오는 이를 사용하여 활성화해야 하는 구성 파일을 지정하는 것입니다🎜rrreee🎜그러나 일반적으로 구성 매개변수를 직접 사용하는 것으로 충분하므로 이 작업을 수행하는 사람은 거의 없습니다. 이것이 필요한 시나리오는 무엇입니까? 🎜🎜물론 그렇습니다. 예를 들어 현재 널리 사용되는 Docker 컨테이너 배포에서는 매번 동일한 이미지를 빌드하고 실제 작업 중에 현재 이미지에서 활성화할 구성 파일을 결정할 수 있습니다. 다양한 환경에 따라 유용합니다🎜🎜예를 들어, 현재 실행 중인 환경을 얻기 위해 app.env 컨테이너의 환경 매개변수를 사용합니다. prod.yml ; 테스트라면 application-test.yml을 활성화하세요🎜🎜그럼 지금 하시면 됩니다🎜rrreee

위 내용은 SpringBoot 컨테이너가 새로 고쳐지기 전에 ApplicationContextInitializer를 다시 호출하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제