个人博客导航页(点击右侧链接即可打开个人博客):大牛带你入门技术栈
1.介绍
ApplicationContextInitializer主要用在容器刷新之前调用改接口实现类的initialize方法,并将ConfigurableApplicationContext类的实例作为参数传入。通常用于根据应用上下文进行处理的编程中。且实现类可以通过Ordered接口或 @Order注解 进行多个Initializer的排序。
2.有三种使用方式
首先定义一个测试initializer
public class TestApplicationContextInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("Initializer调用:" + applicationContext.getApplicationName());
}
@Override
public int getOrder() {
return 0;
}
}
第一种:在启动类的main方法中使用
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
// SpringApplication.run(DemoApplication.class, args);
SpringApplication application = new SpringApplication(DemoApplication.class);
application.addInitializers(new TestApplicationContextInitializer()); // 直接在SpringApplication中添加
application.run(args);
System.out.println("启动完成");
}
}
输出结果:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.5.RELEASE)
Initializer调用:
2020-03-18 19:15:09.448 INFO 87824 --- [ main] com.example.demo.DemoApplication : Starting DemoApplication on ZZ-WZ112019 with PID 87824 (E:\java_work\demo\target\classes started by jiafeng in E:\java_work\demo)
2020-03-18 19:15:09.454 INFO 87824 --- [ main] com.example.demo.DemoApplication : No active profile set, falling back to default profiles: default
2020-03-18 19:15:09.950 INFO 87824 --- [ main] com.example.demo.DemoApplication : Started DemoApplication in 116.167 seconds (JVM running for 116.788)
启动完成
第二种:通过SPI扩展META-INF/spring.factories使用
spring.factories文件
org.springframework.context.ApplicationContextInitializer=\
com.example.demo.initializer.TestApplicationContextInitializer
启动类:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
// SpringApplication application = new SpringApplication(DemoApplication.class);
// application.addInitializers(new TestApplicationContextInitializer()); // 直接在SpringApplication中添加
// application.run(args);
System.out.println("启动完成");
}
}
输出结果:同上产生效果
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.5.RELEASE)
Initializer调用:
2020-03-18 19:20:23.812 INFO 87920 --- [ main] com.example.demo.DemoApplication : Starting DemoApplication on ZZ-WZ112019 with PID 87920 (E:\java_work\demo\target\classes started by jiafeng in E:\java_work\demo)
2020-03-18 19:20:23.814 INFO 87920 --- [ main] com.example.demo.DemoApplication : No active profile set, falling back to default profiles: default
2020-03-18 19:20:24.057 INFO 87920 --- [ main] com.example.demo.DemoApplication : Started DemoApplication in 0.443 seconds (JVM running for 0.932)
启动完成
第三种:通过配置文件使用
在配置文件application.properties中添加如下配置:
context.initializer.classes=com.example.demo.initializer.TestApplicationContextInitializer
运行启动类,依然被调用。
3. Ordered排序
通过继承Ordered接口实现int getOrder()方法进行排序,设置高优先级排序则在众多initializer中会被优先调用。
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
4. 源码分析initializer运行时机
SpringApplication实例化对象时会对所有initializer进行加载。
SpringApplication的run( )方法:
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//刷新之前准备工作,在该方法进行initialize调用
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//进行刷新
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
prepareContext( )方法中
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
//执行initialize调用
applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// 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);
}
在applyInitializers( )方法中对前面加载的initializer进行循环遍历调用initialize方法
@SuppressWarnings({ "rawtypes", "unchecked" })
protected void applyInitializers(ConfigurableApplicationContext context) {
//遍历SpringApplication实例化时加载的所有initializer
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);//调用initialize实现方法
}
}
附Java/C/C++/机器学习/算法与数据结构/前端/安卓/Python/程序员必读/书籍书单大全:
(点击右侧 即可打开个人博客内有干货):技术干货小栈
=====>>①【Java大牛带你入门到进阶之路】<<====
=====>>②【算法数据结构+acm大牛带你入门到进阶之路】<<===
=====>>③【数据库大牛带你入门到进阶之路】<<=====
=====>>④【Web前端大牛带你入门到进阶之路】<<====
=====>>⑤【机器学习和python大牛带你入门到进阶之路】<<====
=====>>⑥【架构师大牛带你入门到进阶之路】<<=====
=====>>⑦【C++大牛带你入门到进阶之路】<<====
=====>>⑧【ios大牛带你入门到进阶之路】<<====
=====>>⑨【Web安全大牛带你入门到进阶之路】<<=====
=====>>⑩【Linux和操作系统大牛带你入门到进阶之路】<<=====天下没有不劳而获的果实,望各位年轻的朋友,想学技术的朋友,在决心扎入技术道路的路上披荆斩棘,把书弄懂了,再去敲代码,把原理弄懂了,再去实践,将会带给你的人生,你的工作,你的未来一个美梦。