ApplicationListener和SpringApplicationRunListener的联系

前言

ApplicationListener接口属于package org.springframework.context;
SpringApplicationRunListener接口属于package org.springframework.boot;
从《SpringBoot技术内幕》一书中得知:

ApplicationContext通过ApplicationListener监听ApplicationEvent

该书是在介绍SpringBoot项目中的SpringApplication.run()方法的构造方法时讲的,SpringApplication的构造方法如下:

	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		// 传app类型,有NONE、SERVLET、REACTIVE三种
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		// 设置ApplicationContextInitializer,加载classpath的META-INF文件夹的spring.fatories文件中找以ApplicationContextInitializer.class为key的value类
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		// 设置ApplicationListener,加载classpath的META-INF文件夹的spring.fatories文件中找以ApplicationListener.class为key的value类
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}

但是,我看了看源码,只找到了ApplicationListener的创建,却看不到调用,然后强迫症就犯了,得找出来。
于是,我做了下面的实验。

实验

在这里插入图片描述

这两个自定义类代码如下:

public class MyApplicationListener implements ApplicationListener {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println("MyApplicationListener执行了监听到了"+event.getClass().getSimpleName());
    }
}
public class MySpringApplicationRunListener implements SpringApplicationRunListener, PriorityOrdered {

    // 必须有这个签名的构造方法,否则会报错
    public MySpringApplicationRunListener(SpringApplication application, String[] args) {
        System.out.println("MySpringApplicationRunListener 构造方法执行");
    }
    @Override
    public void starting() {
        System.out.println("MySpringApplicationRunListener starting方法执行");
    }
    @Override
    public void environmentPrepared(ConfigurableEnvironment environment) {
        System.out.println("MySpringApplicationRunListener environmentPrepared方法执行");
    }
    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        System.out.println("MySpringApplicationRunListener contextPrepared方法执行");
    }
    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        System.out.println("MySpringApplicationRunListener contextLoaded方法执行");
    }
    @Override
    public void started(ConfigurableApplicationContext context) {
        System.out.println("MySpringApplicationRunListener started方法执行");
    }
    @Override
    public void running(ConfigurableApplicationContext context) {
        System.out.println("MySpringApplicationRunListener running方法执行");
    }
    @Override
    public void failed(ConfigurableApplicationContext context, Throwable exception) {
        System.out.println("MySpringApplicationRunListener failed方法执行");

    }
    @Override
    public int getOrder() {
        return 0;
    }
}

执行结果如下:
在这里插入图片描述

理解

先来看看这两个接口的注释:
ApplicationListener:

Interface to be implemented by application event listeners.
Based on the standard java.util.EventListener interface for the Observer design pattern.
As of Spring 3.0, an ApplicationListener can generically declare the event type that it is interested in. When registered with a Spring ApplicationContext, events will be filtered accordingly, with the listener getting invoked for matching event objects only.

SpringApplicationRunListener:

Listener for the SpringApplication run method. SpringApplicationRunListeners are loaded via the SpringFactoriesLoader and should declare a public constructor that accepts a SpringApplication instance and a String[] of arguments. A new SpringApplicationRunListener instance will be created for each run.

可以看到,ApplicationListener:属于context包,应用更加广泛;而SpringApplicationRunListener只是Listener for the SpringApplication run method。
通过调试也可以发现,ApplicationListener不是在SpringBoot项目中直接调用执行的,而是通过org.springframework.boot.context.event.EventPublishingRunListener implements SpringApplicationRunListener类中的成员SimpleApplicationEventMulticaster来反射执行的。整个顺序如下:

  1. SpringApplication构造函数spring.fatories中加载所有的ApplicationListener
  2. SpringApplicationrun方法中 从spring.fatories中加载所有 SpringApplicationRunListener,这其中会加载了一个org.springframework.boot.context.event.EventPublishingRunListener implements SpringApplicationRunListener。将步骤1中所有的ApplicationListener通过构造方法传给EventPublishingRunListener
  3. 看下图两张图,一个是run方法代码,一个是SpringApplicationRunListener的几个接口方法在*run*方法的生命周期的触发时机。
    在这里插入图片描述
    在这里插入图片描述

在看看EventPublishingRunListener类:

public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
	// 通过SpringApplication来获取所有的ApplicationListener
	private final SpringApplication application;
	private final String[] args;
	// 真正ApplicationListener的执行者
	private final SimpleApplicationEventMulticaster initialMulticaster;

	public EventPublishingRunListener(SpringApplication application, String[] args) {
		this.application = application;
		this.args = args;
		this.initialMulticaster = new SimpleApplicationEventMulticaster();
		// 重点代码
		for (ApplicationListener<?> listener : application.getListeners()) {
			this.initialMulticaster.addApplicationListener(listener);
		}
	}
	@Override
	public void starting() {
		// multicastEvent执行所有ApplicationListener接口方法
		this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
	}

	@Override
	public void environmentPrepared(ConfigurableEnvironment environment) {
		// multicastEvent执行所有ApplicationListener接口方法
		this.initialMulticaster
				.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
	}

	@Override
	public void contextPrepared(ConfigurableApplicationContext context) {
		// multicastEvent执行所有ApplicationListener接口方法
		this.initialMulticaster
				.multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
	}

	@Override
	public void contextLoaded(ConfigurableApplicationContext context) {
		for (ApplicationListener<?> listener : this.application.getListeners()) {
			if (listener instanceof ApplicationContextAware) {
				((ApplicationContextAware) listener).setApplicationContext(context);
			}
			context.addApplicationListener(listener);
		}
		// multicastEvent执行所有ApplicationListener接口方法
		this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
	}

	...

}

也就是说,在SpringBoot项目中ApplicationListenerEventPublishingRunListener implements SpringApplicationRunListener代理执行了

整个调用方式如下图:
在这里插入图片描述
大概就这样。回头看多一点再来补充

  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

T.Y.Bao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值