- ApplicationContextInitializer接口的作用就是在spring prepareContext的时候做一些初始化工作
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(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);
}
}
在spring 初始化的过程中 执行prepareContext方法的时候里面会通过applyInitializers方法回调所有ApplicationContextInitializer接口的实现
现在有个疑问?ApplicationContextInitializer接口的实现类是什么时候初始化的,回答这个问题就需要看springboot中SpringApplication的构造方法
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = deduceWebApplicationType();
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
- 构造方法中执行了setInitializers方法该方法是把初始化的ApplicationContextInitializer实现类全部加载到SpringApplication内部的集合中。
- 通过getSpringFactoriesInstances(
ApplicationContextInitializer.class)方法获得实现类
// 获得ApplicationContextInitializer接口的全部实现类
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// Use names and ensure unique to protect against duplicates
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 static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
// 从全部的配置类中获得ApplicationContextInitializer的实现类
return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
// 获得本地spring.factories和jar文件spring.factories 中配置的全部信息
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
List<String> factoryClassNames = Arrays.asList(
StringUtils.commaDelimitedListToStringArray((String) entry.getValue()));
result.addAll((String) entry.getKey(), factoryClassNames);
}
}
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
从这边可以看出Spring从本地的META-INF/spring.factories文件和jar文件中的META-INF/spring.factories 文件获取配置的初始化类(注意这边是获取了配置文件的全部配置类),然后通过loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}方法获得ApplicationContextInitializer接口全部实现类的完整名称
最后通过反射的机制获得ApplicationContextInitializer实现类
DelegatingApplicationContextInitializer
这边有一个比较特殊的ApplicationContextInitializer实现类就是DelegatingApplicationContextInitializer
这个类的作用从名字可以看出是ApplicationContextInitializer的一个委派具体是啥意思?
我们从源码出发:
// spring初始化的时候回调
@Override
public void initialize(ConfigurableApplicationContext context) {
ConfigurableEnvironment environment = context.getEnvironment();
List<Class<?>> initializerClasses = getInitializerClasses(environment);
if (!initializerClasses.isEmpty()) {
applyInitializerClasses(context, initializerClasses);
}
}
// 从property文件中获得ApplicationContextInitializer的实现类的class对象
private List<Class<?>> getInitializerClasses(ConfigurableEnvironment env) {
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;
}
从这方法可以看出当spring 初始化的时候回调
ApplicationContextInitializer的时候 DelegatingApplicationContextInitializer会获得spring的坏境信息然后从环境信息里面获得所有的ApplicationContextInitializer实现类class对象
private void applyInitializerClasses(ConfigurableApplicationContext context,
List<Class<?>> initializerClasses) {
Class<?> contextClass = context.getClass();
List<ApplicationContextInitializer<?>> initializers = new ArrayList<>();
for (Class<?> initializerClass : initializerClasses) {
initializers.add(instantiateInitializer(contextClass, initializerClass));
}
applyInitializers(context, initializers);
}
private void applyInitializers(ConfigurableApplicationContext context,
List<ApplicationContextInitializer<?>> initializers) {
initializers.sort(new AnnotationAwareOrderComparator());
for (ApplicationContextInitializer initializer : initializers) {
initializer.initialize(context);
}
}
然后通过反射的机制生成ApplicationContextInitializer的实现类 最后执行回调initialize方法
从上面我们可以看出实现我们自己的ApplicationContextInitializer实现类我们可以直接实现ApplicationContextInitializer接口具体让其初始化的方式有3种
- 1 在我们项目的spring.factories配置我们的类信息
org.springframework.boot.SpringApplicationRunListener=com.example.demo.MySpringApplicationRunListener
- 2 在启动类中直接加入我们配置的类信息
SpringApplication springApplication = new SpringApplication(DemoApplication.class);
springApplication.addInitializers(new MyApplicationContextInitializer());
springApplication.run(args);
- 3 在我们项目的application.properties文件中加入类信息
context.initializer.classes=com.example.demo.MyApplicationContextInitializer
第一种和第二种方式是在spring初始化的时候直接调用的,然后第三种实在spring初始化的时候通过DelegatingApplicationContextInitializer 实现类来进行调用的
springboot 启动的时候一共加载了6个ApplicationContextInitializer的实现类 分别是:
- 第一个前面已经介绍过 是一个委托的初始化。
- 第二个ContextIdApplicationContextInitializer
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
ContextId contextId = getContextId(applicationContext);
applicationContext.setId(contextId.getId());
applicationContext.getBeanFactory().registerSingleton(ContextId.class.getName(),
contextId);
}
第二个从源码可以看出是给上下文设置了一个id 并且像bean工厂中注册了一个ContextId单列对象
- 第三个ConfigurationWarningsApplicationContextInitializer
@Override
public void initialize(ConfigurableApplicationContext context) {
context.addBeanFactoryPostProcessor(
new ConfigurationWarningsPostProcessor(getChecks()));
}
主要实在上下文中设置了ConfigurationWarningsPostProcessor 类
- 第四个ServerPortInfoApplicationContextInitializer
public class ServerPortInfoApplicationContextInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext>,
ApplicationListener<WebServerInitializedEvent>
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.addApplicationListener(this);
}
从类的定义上可以看出他是一个实现了ApplicationListener接口的监听器 主要负责WebServerInitializedEvent事件的监听,该类初始化的时候主要是把自己加入了上下文的监听中去
- 第五个 SharedMetadataReaderFactoryContextInitializer
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.addBeanFactoryPostProcessor(
new CachingMetadataReaderFactoryPostProcessor());
}
主要是在上下文中加入了CachingMetadataReaderFactoryPostProcessor
- 第六个 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());
}
}
主要是在上下文中加入了ConditionEvaluationReportListener监听器 并生成了ConditionEvaluationReport对象