ApplicationListener是如何生效的

SpringApplication的屬性

	private List<ApplicationListener<?>> listeners;

 

	// org.springframework.boot.SpringApplication.SpringApplication(ResourceLoader, Class<?>...)
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		...省略
		// 根據反射實例化ApplicationListener實現類,設置爲SpringApplication屬性
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}
	public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {
		this.listeners = new ArrayList<>();
		this.listeners.addAll(listeners);
	}
	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
		return getSpringFactoriesInstances(type, new Class<?>[] {});
	}

	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = getClassLoader();
		// Use names and ensure unique to protect against duplicates
		Set<String> names = new LinkedHashSet<>(
				SpringFactoriesLoader.loadFactoryNames(type, classLoader));

		// 根據反射調用ApplicationListener實現類
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
				classLoader, args, names);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

 

// org.springframework.boot.SpringApplication.run(String...)
	public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
		// 獲取到SpringApplicationRunListeners
		SpringApplicationRunListeners listeners = getRunListeners(args);

		// SpringApplicationRunListeners.starting(),
		// 其實是遍歷執行startingSpringApplicationRunListener的starting()
		listeners.starting();

		...

		// 和starting方法一樣
		listeners.started(context);

		return context;
	}
// org.springframework.boot.SpringApplication.getRunListeners(String[])
	private SpringApplicationRunListeners getRunListeners(String[] args) {

		// 根據反射調用SpringApplicationRunListener實現類的帶參構造器
		// 默認實現類是org.springframework.boot.context.event.EventPublishingRunListener
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
				SpringApplicationRunListener.class, types, this, args));

	}

// org.springframework.boot.SpringApplicationRunListeners
	public void starting() {

		for (SpringApplicationRunListener listener : this.listeners) {
// 遍歷所有的SpringApplicationRunListener實例的starting()方法,其他方法類似
			listener.starting();
		}

	}
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
	// 構造方法,反射調用
	public EventPublishingRunListener(SpringApplication application, String[] args) {
		this.application = application;
		this.args = args;
		// 創建一個applicationEvent事件多播器,可以進行廣播,即遍歷每個ApplicationListener
		this.initialMulticaster = new SimpleApplicationEventMulticaster();

		// 將SpringApplictaion對象的中的屬性listeners(ApplicationListener集合)設置到多播器中
		for (ApplicationListener<?> listener : application.getListeners()) {
			this.initialMulticaster.addApplicationListener(listener);
		}
	}
}

 

public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {

	...

	@Override
	public void starting() {
		// 調用多播器廣播事件
		this.initialMulticaster.multicastEvent(
				new ApplicationStartingEvent(this.application, this.args));
	}

	...

	@Override
	public void contextLoaded(ConfigurableApplicationContext context) {
		// 遍歷SpringApplication中的ApplicationListener集合,設置到context中,查看AbstractApplicationContext.registerListeners()方法會去使用getApplicationListeners獲取
		for (ApplicationListener<?> listener : this.application.getListeners()) {
			if (listener instanceof ApplicationContextAware) {
				((ApplicationContextAware) listener).setApplicationContext(context);
			}
			// 準備好context容器,下一步是要調用AbstractApplicationContext的refresh方法
			// 在refresh方法中的initApplicationEventMulticaster方法會初始化Spring自己的多播器,當前類的多播器是屬於springboot的
			context.addApplicationListener(listener);
		}
		// 調用多播器廣播事件
		this.initialMulticaster.multicastEvent(
				new ApplicationPreparedEvent(this.application, this.args, context));
	}

	@Override
	public void started(ConfigurableApplicationContext context) {
		// 調用spring容器的廣播事件,後面的running,failed一樣
		context.publishEvent(
				new ApplicationStartedEvent(this.application, this.args, context));
	}

	...

}
// org.springframework.context.support.AbstractApplicationContext.initApplicationEventMulticaster()
	protected void initApplicationEventMulticaster() {
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
			this.applicationEventMulticaster =
					beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
			if (logger.isTraceEnabled()) {
				logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
			}
		}
		else {
			this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
			beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
			if (logger.isTraceEnabled()) {
				logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
						"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
			}
		}
	}

// org.springframework.context.support.AbstractApplicationContext.registerListeners()
	protected void registerListeners() {
		// Register statically specified listeners first.
// 之前在org.springframework.boot.context.event.EventPublishingRunListener.contextLoaded(ConfigurableApplicationContext)設置進容器的
		for (ApplicationListener<?> listener : getApplicationListeners()) {
			getApplicationEventMulticaster().addApplicationListener(listener);
		}

		// Do not initialize FactoryBeans here: We need to leave all regular beans
		// uninitialized to let post-processors apply to them!
// 從容器中取出用戶放入的ApplicationListener實現類,但是現在不進行初始化
		String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
		for (String listenerBeanName : listenerBeanNames) {
			getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
		}

		// Publish early application events now that we finally have a multicaster...
		Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
		this.earlyApplicationEvents = null;
		if (earlyEventsToProcess != null) {
			for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
				getApplicationEventMulticaster().multicastEvent(earlyEvent);
			}
		}
	}

// org.springframework.context.support.AbstractApplicationContext.getApplicationEventMulticaster()
	ApplicationEventMulticaster getApplicationEventMulticaster() throws IllegalStateException {
		if (this.applicationEventMulticaster == null) {
			throw new IllegalStateException("ApplicationEventMulticaster not initialized - " +
					"call 'refresh' before multicasting events via the context: " + this);
		}
		return this.applicationEventMulticaster;
	}

// org.springframework.context.event.AbstractApplicationEventMulticaster.addApplicationListener(ApplicationListener<?>)
	public void addApplicationListener(ApplicationListener<?> listener) {
		synchronized (this.retrievalMutex) {
			// Explicitly remove target for a proxy, if registered already,
			// in order to avoid double invocations of the same listener.
			Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
			if (singletonTarget instanceof ApplicationListener) {
				this.defaultRetriever.applicationListeners.remove(singletonTarget);
			}
			this.defaultRetriever.applicationListeners.add(listener);
			this.retrieverCache.clear();
		}
	}
// org.springframework.context.event.AbstractApplicationEventMulticaster.addApplicationListenerBean(ApplicationListener<?>)
	@Override
	public void addApplicationListenerBean(String listenerBeanName) {
		synchronized (this.retrievalMutex) {
			this.defaultRetriever.applicationListenerBeans.add(listenerBeanName);
			this.retrieverCache.clear();
		}
	}

// org.springframework.context.event.AbstractApplicationEventMulticaster.ListenerRetriever
	private class ListenerRetriever {

		public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();

		public final Set<String> applicationListenerBeans = new LinkedHashSet<>();
		...
	}

 


ApplicationListener接口定義

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

	/**
	 * Handle an application event.
	 * @param event the event to respond to
	 */
	void onApplicationEvent(E event);

}

SpringApplicationRunListener接口定義

public interface SpringApplicationRunListener {

	/**
	 * Called immediately when the run method has first started. Can be used for very
	 * early initialization.
	 */
	void starting();

	/**
	 * Called once the environment has been prepared, but before the
	 * {@link ApplicationContext} has been created.
	 * @param environment the environment
	 */
	void environmentPrepared(ConfigurableEnvironment environment);

	/**
	 * Called once the {@link ApplicationContext} has been created and prepared, but
	 * before sources have been loaded.
	 * @param context the application context
	 */
	void contextPrepared(ConfigurableApplicationContext context);

	/**
	 * Called once the application context has been loaded but before it has been
	 * refreshed.
	 * @param context the application context
	 */
	void contextLoaded(ConfigurableApplicationContext context);

	/**
	 * The context has been refreshed and the application has started but
	 * {@link CommandLineRunner CommandLineRunners} and {@link ApplicationRunner
	 * ApplicationRunners} have not been called.
	 * @param context the application context.
	 * @since 2.0.0
	 */
	void started(ConfigurableApplicationContext context);

	/**
	 * Called immediately before the run method finishes, when the application context has
	 * been refreshed and all {@link CommandLineRunner CommandLineRunners} and
	 * {@link ApplicationRunner ApplicationRunners} have been called.
	 * @param context the application context.
	 * @since 2.0.0
	 */
	void running(ConfigurableApplicationContext context);

	/**
	 * Called when a failure occurs when running the application.
	 * @param context the application context or {@code null} if a failure occurred before
	 * the context was created
	 * @param exception the failure
	 * @since 2.0.0
	 */
	void failed(ConfigurableApplicationContext context, Throwable exception);

}

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章