最近再看SpringBoot的源码,在调用refreshContext(context)之前,会对ApplicationContextInitializer的实现类等进行调用.所以写一篇文章来进行记录
话不多话,先上代码,当然这里直接实现,在SpringBoot并不会启动,我们采用第一种方式来指定
No 1 :
package com.yang.threadspringcase.initializer;
/*
*@author:BaoYang
*@Date: 2020/2/26
*@description:
*/
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import java.util.HashMap;
import java.util.Map;
public class FirstInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>
{
@Override
public void initialize(ConfigurableApplicationContext applicationContext)
{
ConfigurableEnvironment contextEnvironment = applicationContext.getEnvironment();
// contextEnvironment.setRequiredProperties("yang");
Map<String,Object> map = new HashMap<>();
map.put("key1","value1");
MapPropertySource mapPropertySource = new MapPropertySource("firstInitializer",map);
contextEnvironment.getPropertySources().addLast(mapPropertySource);
System.out.println("FirstInitializer Add ....");
}
}
这里我们在resources下面,创建一个META-INF目录,
org.springframework.context.ApplicationContextInitializer=com.yang.threadspringcase.initializer.FirstInitializer
然后使用这句话来指定即可,这是第一种配置方式.
No 2 : 第二个我们还是回继续实现 ApplicationContextInitializer接口.
package com.yang.threadspringcase.initializer;
/*
*@author:BaoYang
*@Date: 2020/2/29
*@description:
*/
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import java.util.HashMap;
import java.util.Map;
public class SecondInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>
{
@Override
public void initialize(ConfigurableApplicationContext applicationContext)
{
ConfigurableEnvironment environment = applicationContext.getEnvironment();
Map<String,Object> map = new HashMap<>();
map.put("key2", "value2");
MapPropertySource mapPropertySource = new MapPropertySource("secondInitializer", map);
environment.getPropertySources().addLast(mapPropertySource);
System.out.println("SecondInitializer Init Over");
}
}
当然也需要指定一下, 这回指定类的地方,我们换一下,在application.properties中
在 application.properties中
context.initializer.classes=com.yang.threadspringcase.initializer.SecondInitializer
使用这句来指定即可.
No 3 这里来第三种. 依然还是实现同样的接口
package com.yang.threadspringcase.initializer;
/*
*@author:BaoYang
*@Date: 2020/2/29
*@description:
*/
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import java.util.HashMap;
import java.util.Map;
public class ThreeInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>
{
@Override
public void initialize(ConfigurableApplicationContext applicationContext)
{
ConfigurableEnvironment environment = applicationContext.getEnvironment();
Map<String,Object> map = new HashMap<>();
map.put("key3", "value3");
MapPropertySource mapPropertySource = new MapPropertySource("threeInitializer", map);
environment.getPropertySources().addLast(mapPropertySource);
System.out.println("ThreeInitializer Init Over");
}
}
这回就直接加在代码里面来实现
SpringApplication springApplication = new SpringApplication(ThreadSpringCaseApplication.class);
springApplication.addInitializers(new ThreeInitializer());
ConfigurableApplicationContext context = springApplication.run(args);
String key3 = context.getEnvironment().getProperty("key3");
System.out.println(key3);
将启动的类修改为这样,第三种方式就可以了。
然后,我们启动一下项目就可以看到相应的效果了
然后就可以看到,三句胡乱打印的Log。细心的朋友就不难猜出,Initializer的加载顺序了,先从 application.properties中加载,再从META-INF/配置下加载 , 再从代码中add中加载.
我们再来debug看看.
直接将断点打在 SpringApplication ---> 314行, 如下的方法上
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
然后debug启动,发现并没有打印 Initializer 中的内容
debug到 SpringApplication 621行
applyInitializers(ConfigurableApplicationContext context) ---> getInitializers()
这个就可以看到 initializers中已经有的Initialzers实现类信息,但是自信看下来,居然没有SecoedInitialzer的信息。然后debug一步一步的看.
当我们debug第一个
DelegatingApplicationContextInitializer.initialize() ---> getInitializerClasses(environment)
这个方面从之前的环境加载之中加载从配置文件中配置的信息, 然后继续调用 SecondInitializer 中的 initialize方法
走完这个方法就可以看到控制输出 SecondInitializer Init Over 这句话
然后九个中的第一个走完,然后回一次走完剩下的八个.
这里分析完了,就可以看到SpringBoot源码再执行Initializer的实现类执行过程。然后跟我们的打印顺序一起关联起来就即可。
由于我目前很少使用 ApplicationContextInitializer 来加载东西,所以对于深入进去的内容并不是很了解。
目前了解的一般这样配置会在初始化Bean之前,加载好配置文件等信息功能。