ApplicationListener

一、简介

  • ApplicationListener接口是spring框架为开发者提供的一个扩展点。一般来说,一个我们新建一个项目,在启动时就需要初始化一些东西的(比如数据库的数据,一个对象,或者是某些配置)。并且使用ApplicationListener后可以拿到spring容器,功能是异常强大,好用。

二、使用

  • ApplicationRefreshedListener.java
@Component
public class ApplicationRefreshedListener implements ApplicationListener{

	@Override
	public void onApplicationEvent(ContextRefreshedEvent event) {

		System.out.println("我的父容器为:" + event.getApplicationContext().getParent());
		 
	      System.out.println("初始化时我被调用了。" + event.getApplicationContext().getDisplayName());
	      //第一个方法 排除子容器 只要老大 没有parent,他就是老大
	      if(null == event.getApplicationContext().getParent()){
		      //TODO 写自己的业务逻辑
		      System.out.println( "---------");
	      }
	}

}

三、源码解析

  • AbstractApplicationContext#refresh方法
public void refresh() throws BeansException, IllegalStateException {
	 			........省略
				// Initialize event multicaster for this context.
				 // 初始化当前 ApplicationContext 的事件广播器 
				initApplicationEventMulticaster();
 	          ......省略
 	          // Last step: publish corresponding event.
				// 最后,广播事件,ApplicationContext 初始化完成
				finishRefresh();
				.......省略
	}
  • AbstractApplicationContext#finishRefresh
protected void finishRefresh() {
		// Initialize lifecycle processor for this context.
		initLifecycleProcessor();

		// Propagate refresh to lifecycle processor first.
		getLifecycleProcessor().onRefresh();

		// Publish the final event.
		//发布ContextRefreshedEvent事件
		publishEvent(new ContextRefreshedEvent(this));

		// Participate in LiveBeansView MBean, if active.
		LiveBeansView.registerApplicationContext(this);
	}
  • AbstractApplicationContext#publishEvent
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);
		//判断当前ApplicationContext有没有父级 ,如果有执行父级调用publishEvent 所以ApplicationListener被多次执行了
		if (this.parent != null) {
			this.parent.publishEvent(event);
		}
	}
  • SimpleApplicationEventMulticaster#multicastEvent
public void multicastEvent(final ApplicationEvent event) {
      //getApplicationListeners  得到是event这个类型的事件列表,event在这里是ContextRefreshedEvent
		for (final ApplicationListener listener : getApplicationListeners(event)) {
			Executor executor = getTaskExecutor();
			if (executor != null) {
				executor.execute(new Runnable() {
					public void run() {
						//线程池执行onApplicationEvent 方法
						listener.onApplicationEvent(event);
					}
				});
			}
			else {
				//直接执行onApplicationEvent 方法
				listener.onApplicationEvent(event);
			}
		}
	}

关于ApplicationListener的类会执行多次的原因

  • 我自己测试了下某些情况下会执行多次,如下图
    ApplicationListener_第1张图片
    ApplicationListener_第2张图片
  • 在之前一篇文件就提过如果使用

org.springframework.web.context.ContextLoaderListener

会产生2个容器,有父子关系,详情可见spring报错parsing XML document from ServletContext resource [/WEB-INF/applicationContext.xml]

  • 通过代码也就不难解释了,这里有个递归。
//判断当前ApplicationContext有没有父级 ,如果有执行父级调用publishEvent 所以ApplicationListener被多次执行了
		if (this.parent != null) {
			this.parent.publishEvent(event);
		}
  • 要避免重复调用的问题,上面已经写了,加个判断就可以了。

你可能感兴趣的:(java,spring,Spring入门及源码分析)