ApplicationListener被多次加载的问题

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

    }
}
  1. 确定ApplicationListener是针对哪种特定ApplicationEvent进行监听
  2. 同时集成了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

转载于:https://my.oschina.net/u/3434392/blog/1826157

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值