ApplicationContextInitializer

在何处执行?

执行时机在SpringApplication类的prepareContenxt中,在run方法中可以找到prepareContext方法。

private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
			ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments, Banner printedBanner) {
	...
	// 执行applyInitializers
	applyInitializers(context);
	...
}

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

何时初始化?

在SpringApplication构造函数中会初始化initializers。

@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    ...
	// 初始化initializers
	setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
	...
}

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
	return getSpringFactoriesInstances(type, new Class<?>[] {});
}

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
	ClassLoader classLoader = getClassLoader();
	// 在META-INF/spring.factories中寻找实现类。
	Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
	List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
	AnnotationAwareOrderComparator.sort(instances);
	return instances;
}

自己写一个ApplicationContextInitializer

public class OrangeInitializer implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("my initializer");
    }
}

在resources的META-INF中创建一个spring.factories文件,下面是我的例子,具体的路径还是看自己的。

org.springframework.context.ApplicationContextInitializer=\
  com.example.spring.spring.listener.OrangeInitializer

可以看到启动SpringBoot之后,my initializer打印出来了。
在这里插入图片描述

那这个类的设计具体有什么作用呢??

想要知道这里类的作用,切入点就是看看它的实现类都干了什么事情,下面八个类,有一个OrangeInitializer是自定义的,其他七个是SpringBoot启动就有的。当然也可以从名称上去猜测,他就是用来初始化ApplicationContext的。看一下它的默认实现都干了什么事情!

在这里插入图片描述

1. DelegatingApplicationContextInitializer

private static final String PROPERTY_NAME = "context.initializer.classes";

@Override
public void initialize(ConfigurableApplicationContext context) {
	ConfigurableEnvironment environment = context.getEnvironment();
	// 获取对象
	List<Class<?>> initializerClasses = getInitializerClasses(environment);
	// 执行具体的ApplicationContextInitializer
	if (!initializerClasses.isEmpty()) {
		applyInitializerClasses(context, initializerClasses);
	}
}

private List<Class<?>> getInitializerClasses(ConfigurableEnvironment env) {
    // 从Environment中拿context.initializer.classes。
	String classNames = env.getProperty(PROPERTY_NAME);
	List<Class<?>> classes = new ArrayList<>();
	if (StringUtils.hasLength(classNames)) {
		for (String className : StringUtils.tokenizeToStringArray(classNames, ",")) {
			classes.add(getInitializerClass(className));
		}
	}
	return classes;
}

通过配置文件去注入ApplicationContextInitializer。

public class EnvironmentInitializer implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("my environmentInitializer");
    }
}

application.yml如果自己有多个类,可以用英文逗号隔开

context:
  initializer:
    classes: com.example.spring.spring.initializer.EnvironmentInitializer

在这里插入图片描述

2. SharedMetadataReaderFactoryContextInitializer

这个就简单多了,就把一个BeanFactoryPostProcessor放入到ConfigurableApplicationContext中,会在AbstractApplicationContext的refresh的invokeBeanFactoryPostProcessors去执行。

@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
	BeanFactoryPostProcessor postProcessor = new CachingMetadataReaderFactoryPostProcessor(applicationContext);
	applicationContext.addBeanFactoryPostProcessor(postProcessor);
}

3. ContextIdApplicationContextInitializer

也不知道作用是啥。

@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
	ContextId contextId = getContextId(applicationContext);
	applicationContext.setId(contextId.getId());
	applicationContext.getBeanFactory().registerSingleton(ContextId.class.getName(), contextId);
}

4. ConfigurationWarningsApplicationContextInitializer

也是添加一个BeanFactoryPostProcessor处理器。

@Override
public void initialize(ConfigurableApplicationContext context) {
	context.addBeanFactoryPostProcessor(new ConfigurationWarningsPostProcessor(getChecks()));
}

5. RSocketPortInfoApplicationContextInitializer

不知道是干什么的

6. ServerPoerInfoApplicationContextInitializer

7. ConditionEvaluationReportLoggingListener

不知道

@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
	this.applicationContext = applicationContext;
	applicationContext.addApplicationListener(new ConditionEvaluationReportListener());
	if (applicationContext instanceof GenericApplicationContext) {
		// Get the report early in case the context fails to load
		this.report = ConditionEvaluationReport.get(this.applicationContext.getBeanFactory());
	}
}

总结

  1. ApplicationContextInitializer是用来填充ApplicationContext各种属性的
  2. 在refresh之前执行
  3. 有spring.factories / application.yml两种方法进行自定义扩展