import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class ParamsContextAdapter implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
try {
// 生成了两个AnnotationConfigApplicationContext子容器;
//父容器为AnnotationConfigEmbeddedWebApplicationContext;
//祖父容器为AnnotationConfigApplicationContext
ApplicationContext child = event.getApplicationContext();
ApplicationContext parent = event.getApplicationContext().getParent();
ApplicationContext grandParent = parent != null ? parent.getParent() : null;
log.info("当前:{}; 父亲:{}; 祖父:{}", child.getDisplayName(), parent == null ? null : parent.getDisplayName(),
grandParent == null ? null : grandParent.getDisplayName());
if (event.getApplicationContext().getParent().getParent() == null) {
log.info("初始化适配器开始");
System.out.println("test ApplicationListener");
log.info("初始化适配器完成");
}
} catch (Exception e) {
log.error("初始化适配器异常", e);
}
}
}
- 确定ApplicationListener是针对哪种特定ApplicationEvent进行监听
-
同时集成了spring和springMVC的话,上下文中会存在父、子容器,
(spring配置文件的<context-param>contextConfigLocation的父容器和springMVC配置文件的<init-param>contextConfigLocation的子容器), 在通过applicationContext发送通知的时候,事件可能会被两个容器同时发布。可以先排除是否由于配置有误造成。再@Override public void onApplicationEvent(ContextRefreshedEvent event) { if(event.getApplicationContext().getParent() == null){ //需要执行的逻辑代码,当spring容器初始化完成后就会执行该方法。 } }
源码解析:
如果父容器不为空,父容器也publish事件源,所以生成了几次容器也对执行有影响
核心代码:
AbstractApplicationContext.refresh(); ---spring容器加载编排
AbstractApplicationContext.finishRefresh: ---- publish event
AbstractApplicationContext.prepareBeanFactory(); ----给beanfactory准备一些Aware或BeanPostProcessor
ApplicationContextAwareProcessor: 一些aware实体类生成前需要的处理
DefaultListableBeanFactory.preInstantiateSingletons(); --- 在refresh()方法编排的finishBeanFactoryInitialization中,创建单例的bean
AbstractAutowireCapableBeanFactory.createBean/doCreateBean/populateBean/initializeBean: 在populateBean中获取创建bean内需要注入的bean。
AbstractApplicationContext:
protected void finishRefresh() {
// Initialize lifecycle processor for this context.
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh();
// Publish the final event. 将上下文ApplicationContext注入到ContextRefreshedEvent中
publishEvent(new ContextRefreshedEvent(this));
}
public void publishEvent(ApplicationEvent event) {
Assert.notNull(event, "Event must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Publishing event in " + getDisplayName() + ": " + event);
}
getApplicationEventMulticaster().multicastEvent(event);
if (this.parent != null) {
this.parent.publishEvent(event); // 如果父容器不为空,父容器也publish事件源
}
}
测试发现springcloud的项目中,生成了3个容器
当前:org.springframework.context.annotation.AnnotationConfigApplicationContext@5cbe72b9;
父亲:org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@20411320;
祖父:org.springframework.context.annotation.AnnotationConfigApplicationContext@5c8eee0f
--------------------------------------------
当前:org.springframework.context.annotation.AnnotationConfigApplicationContext@5ec06e97;
父亲:org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@20411320;
祖父:org.springframework.context.annotation.AnnotationConfigApplicationContext@5c8eee0f
----------------------------------------------
当前:org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@20411320;
父亲:org.springframework.context.annotation.AnnotationConfigApplicationContext@5c8eee0f;
祖父:null