Spring 的扩展点 是Spring易扩展的一个重要体现,熟悉这些扩展点的定义方式,以及其调用时机,不仅成为工作中利器,也能深度理解Spring框架的切入点。
ApplicationContextInitializer接口的扩展点
ApplicationContextInitializer 接口用于在 Spring 容器刷新之前执行的一个回调函数,通常用于向 SpringBoot 容器中注入属性。
来源
org.springframework.context它是由Spring本身提供的原生接口。
package org.springframework.context;
// ConfigurableApplicationContext刷新前的回调接口,一般用在web环境中
// 针对ApplicationContext需要一些程序化定制的场景,比如设置Environment
// 的profile相关环境变量
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
// 初始化给定的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<ConfigurableApplicationContext>
{
@override
public void initialize(ConfigurableApplicationContext applicationContext) (
MutablePropertySources propertySources =
applicationContext.getEnvironment().getPropertySources();
//创建自定义的属性源
Map<String, Object> customProperties = new HashMap<>();
customProperties.put("custom.property","custom value");
MapPropertySource customPropertySource =new MapPropertySource("customPropertySource",customProperties);
//将自定义属性源添加到应用程序上下文的属性源列表中
propertySources.addFirst(customPropertySource);
);
}
伀~众~号和CSDN关注 大齐架构,了解更多架构知识以及人生感悟