ApplicationContextInitializer的加载和使用触发点

本文介绍了SpringBoot中ApplicationContextInitializer的加载触发点,包括其在启动过程中的作用,以及三种主要的实现方式:接口实现、spring.factories文件和application.properties配置。还详细讲述了几个特定初始化器的功能,如处理配置警告、设置应用上下文ID和端口监听等。
摘要由CSDN通过智能技术生成


https://zhuanlan.zhihu.com/p/344973213

public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {

    /**
     * Initialize the given application context.
     * @param applicationContext the application to configure
     */
    void initialize(C applicationContext);

}


####  ---------------------------------------ApplicationContextInitializer的加载和使用触发点
   
ApplicationContextInitializer是在Springboot启动过程(refresh方法前)调用,允许我们对ConfiurableApplicationContext的实例做进一步的设置和处理。
如PropertySourceBootstrapConfiguration类可以在其initialize方法中遍历for (PropertySourceLocator locator : this.propertySourceLocators) 配置的位置,
把配置加入到环境中。

在SpringApplication的构造函数中通过spi机制把实现了ApplicationContextInitializer的类加载进来
-> new SpringApplication()
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class))

调用触发点
-> SpringApplication.run()
-> SpringApplication.prepareContext()
    applyInitializers
-> SpringApplication.applyInitializers()
    protected void applyInitializers(ConfigurableApplicationContext context) {
        for (ApplicationContextInitializer initializer : getInitializers()) {
            Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
                    ApplicationContextInitializer.class);
            Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
            initializer.initialize(context);
        }
    }
-> PropertySourceBootstrapConfiguration.initialize()

    for (PropertySourceLocator locator : this.propertySourceLocators) {
            Collection<PropertySource<?>> source = locator.locateCollection(environment)                NacosPropertySourceLocator把nacos配置加载进来

####  ---------------------------------------ApplicationContextInitializer实现主要有3中方式
 先创建一个类实现ApplicationContextInitializer这个接口,实现对应的方法。
 public class AppInit implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("\ncustom ApplicationContextInitializer is :" + applicationContext.getDisplayName());
    }
 }
 
 1、使用spring.factories方式,在resource下面新建/META-INF/spring.factories文件。
        org.springframework.context.ApplicationContextInitializer=\
        com.yfw.learn.AppInit
        
 2、application.properties添加配置方式:
    对于这种方式是通过DelegatingApplicationContextInitializer这个初始化类中的initialize方法获取到
    application.properties中context.initializer.classes对应的类并执行对应的initialize方法。
    只需要将实现了ApplicationContextInitializer的类添加到application.properties即可。如下:
        context.initializer.classes=com.yfw.learn.AppInit
        
 3、在启动类修改启动方式。
        SpringApplication application = new SpringApplication(TestDemoApplication.class);
        application.addInitializers(new TestContextInitializer());
        application.run(args); 
        
不 过一般 情 况 下 我 们 不 需 要 自 定 义 一 个ApplicationContextInitializer,Spring Boot框架默认也只有以下实现而已:   
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer


ConfigurationWarningsApplicationContextInitializer 用于报告 Spring 容器的一些常见的错误配置,可以看出,
该初始化器为 context 增加了一个 Bean 的后置处理器。这个处理器是在注册 BeanDefinition 实例之后生效的,
用于处理注册实例过程中产生的告警信息,其实就是通过日志打印出告警信息。


ContextIdApplicationContextInitializer用于设置 Spring 应用上下文 ID,这个 ID 可以通过 ApplicationContext#getId() 的方式获得。

DelegatingApplicationContextInitializer 看到 Delegating 就知道了,这个初始化器是为了别人服务的。这个初始化器会获得 application.properties 
下的配置为 context.initializer.classes 的值,这个值是初始化器的全路径名,多个之间用逗号隔开。获得名称后,使用反射将其实例化,
并依次触发初始化器的 initialize 方法。DelegatingApplicationContextInitializer 使得 Spring Boot 的用户可以在 application.properties 中配置初始化器。需要注意的是,DelegatingApplicationContextInitializer 的优先级是 0 ,所以不论 context.initializer.classes 
配置的初始化器的 order 是多少,都会按照 0 的优先级执行。

RSocketPortInfoApplicationContextInitializer 和 ServerPortInfoApplicationContextInitializer 都是给 ApplicationContext 增加了个监听器,
二者都是监听 RSocketServerInitializedEvent 事件,为环境 Environment 中添加一个属性源,不同之处在于一个是增加 SocketPort,一个是增加 ServerPort。

除了 spring-boot 下的 META-INF/spring.factories 存在初始化器外,spring-boot-autoconfigure 下也存在 META-INF/spring.factories。这里也定义了两个初始化器。从这里也可以看出,使用 SPI 的方式确实降低了项目间的耦合,每个项目都能定义自己的实现。
org.springframework.context.ApplicationContextInitializer=
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

  • 17
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值