架构のSpring扩展点(一):上下文创建前的动态处理-ApplicationContextInitializer

Spring 的扩展点 是Spring易扩展的一个重要体现,熟悉这些扩展点的定义方式,以及其调用时机,不仅成为工作中利器,也能深度理解Spring框架的切入点。

ApplicationContextInitializer接口的扩展点


ApplicationContextInitializer 接口用于在 Spring 容器刷新之前执行的一个回调函数,通常用于向 SpringBoot 容器中注入属性。

来源

org.springframework.context它是由Spring本身提供的原生接口。

package org.springframework.context;
// ConfigurableApplicationContext刷新前的回调接口,一般用在web环境中
// 针对ApplicationContext需要一些程序化定制的场景,比如设置Environment
// 的profile相关环境变量
public interface ApplicationContextInitializer {

  // 初始化给定的applicationContext
  void initialize(C applicationContext);

}


Spring内置实现类


ContextIdApplicationContextInitializer


根据下列环境属性设置的值,设置Spring应用上下文的ID 默认值为application

* spring.application.name
* vcap.application.name
* spring.config.name
* spring.application.index
* vcap.application.instance_index  

ServerPortInfoApplicationContextInitializer


将内置 servlet容器实际使用的监听端口写入到 Environment 环境属性中。这样属性 local.server.port 就可以直接通过 @Value 注入到测试中,或者通过环境属性 Environment 获取。

三种实现方式


Spring上下文Context对象注册

@SpringBootApplication
public class SpringbootHelloWorldApplication {

    public static void main(String[] args) {


        SpringApplication springApplication = new SpringApplication(SpringbootHelloWorldApplication.class);
        springApplication.addInitializers(ac -> System.out.println("initializer registered--->"));
        springApplication.run(args);
    }
}


配置文件加载

在application.properties文件中配置如下内容:
context.initializer.classes=dongshi.daddy.contextinitializer.MyContextInitializer。

public class MyContextInitializer implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("initializer registered--->");
    }
}

在spring.factories添加配置

在项目下的resources下新建META-INF文件夹,文件夹下新建spring.factories文件:

org.springframework.context.ApplicationContextInitializer=com.daq.config.MyContextInitializer 

实现Api接口

public class MyContextInitializer1 implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("initializer registered--->");
    }
}


三种方式最终的控制台输出结果都是一样的 .

  ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::       (v2.1.14.RELEASE)

initializer registered--->

Spring内部调用扩展点的原理


org.springframework.boot.SpringApplication#prepareContext,源码如下:

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
      SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
  ......
  // 调用方法
  applyInitializers(context);
  ......
}


调用方法applyInitializers的具体逻辑:

@SuppressWarnings({ "rawtypes", "unchecked" })
protected void applyInitializers(ConfigurableApplicationContext context) {
  // 获取所有的ApplicationContextInitializer,并循环调用其initialize方法
  for (ApplicationContextInitializer initializer : getInitializers()) {
    Class requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
        ApplicationContextInitializer.class);
    Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
    initializer.initialize(context);
  }
}


应用场景

动态加载配置:

您可以在应用程序上下文创建之前加载一些动态的配置,例如从外部配置文件中读取配置信息并注入到Spring的环境中。


执行额外的初始化逻辑:

如果您有一些需要在应用程序上下文启动之前执行的初始化逻辑,例如初始化数据库连接池或启动一些后台任务

public class CustomApplicationContextInitializer implements
            ApplicationContextInitializer 
{
        @override
        public void initialize(ConfigurableApplicationContext applicationContext) (
        MutablePropertySources propertySources =
                applicationContext.getEnvironment().getPropertySources();

        //创建自定义的属性源
        Map customProperties = new HashMap<>();
        customProperties.put("custom.property","custom value");
        MapPropertySource customPropertySource =new MapPropertySource("customPropertySource",customProperties);
        //将自定义属性源添加到应用程序上下文的属性源列表中
        propertySources.addFirst(customPropertySource);
        );
    }

伀~众~号和CSDN关注 大齐架构,了解更多架构知识以及人生感悟

你可能感兴趣的:(Spring扩展点,spring,boot,java,spring,cloud,intellij-idea,开发语言)