2、Springboot之ApplicationContext&Listener&Config

14 篇文章 0 订阅
12 篇文章 0 订阅

Spring Event(Application Event)其实就是一个观察者模式。观察者模式含有主题(针对该主题的事件ApplicationEvent)、发布者、订阅者/监听器。ApplicationEventMulticaster:事件管理者,用于事件监听器的注册和事件的广播。ApplicationEventPublisher:事件发布者,委托ApplicationEventMulticaster完成事件的发布。

SpringBoot根据监听器加载方式主要分为两种:

  1. Spi机制加载得到的。当然用户也可以按照SPI机制规范使用该类型下的监听器。
  2. 自定义IOC容器托管bean的方式。

针对第一种方式:SpringBoot在启动过程中主要存在两种不同类型的监听器即ApplicationListenerSpringApplicationRunListener,这两种监听器都是通过SPI机制得到具体的实现类。
第二种方式:实际使用过程中更多选择ApplicationEventPublisherAware类型的事件发布者实现事件发布机制功能。

SpringBoot根据监听器事件监听触发的时机又分为很多种:

  1. 在刷新容器refresh之前存在一部分事件发布机制,一般是指SPI机制加载得到的监听器。
  2. 在刷新容器refresh过程中,不同时间节点也存在相应的事件发布机制。
  3. 容器被刷新完之后,例如最常见的ContextRefreshedEvent类型事件。

不管监听器是何种加载方式,最终都是由 SimpleApplicationEventMulticaster 触发事件的监听。

SpringBoot内部获取监听器方式存在两种:直接获取全部监听器、根据事件类型获取对应的监听器。这些监听器在SpringBoot应用中可能随着启动流程被触发一次或者多次,主要是根据监听器支持的事件类型决定的。如果选择ApplicationEventPublisherAware实现事件发布者机制则事件触发时机完全取决于web请求。

1.SpringApplicationRunListener

SpringApplicationRunListener接口中相关事件贯穿于Spring启动的整个流程。这个接口的具体实现类除了Spring内置类EventPublishingRunListener,用于也可以自定义该类型的监听器,参与控制Spring启动的整个流程。

public interface SpringApplicationRunListener {
	void starting();
	void environmentPrepared(ConfigurableEnvironment environment);
	void contextPrepared(ConfigurableApplicationContext context);
	void contextLoaded(ConfigurableApplicationContext context);
	void started(ConfigurableApplicationContext context);
	void running(ConfigurableApplicationContext context);
	void failed(ConfigurableApplicationContext context, Throwable exception);
}

具体参考:SpringApplicationRunListeners。

1.1.发布者之EventPublishingRunListener

接口SpringApplicationRunListener不同方法其实对应不同的事件。不同事件的触发最终是被委托给EventPublishingRunListener完成的,其中分别对应ApplicationStartingEvent、ApplicationEnvironmentPreparedEvent、ApplicationContextInitializedEvent、ApplicationPreparedEvent、ApplicationStartedEvent、ApplicationReadyEvent、ApplicationFailedEvent事件类型。这些类型的事件穿插在Spring机制中不同结点处。

其实在当前监听器内部事件的真正发布又一次发生了委托,真正委托对象为SimpleApplicationEventMulticaster

1.1.1.监听器之ApplicationListener

public class SpringApplication {
	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		...
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		//初始化提前约定的全部监听器【约定大于配置】
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
	}
}

利用类加载器加载classpath特定路径【META-INF/spring.factories】下存在的 ApplicationListener 监听器的实现子类。

spring-boot.jar#spring.factories文件:

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

该类型的监听器存在顶级子接口GenericApplicationListener、SmartApplicationListener。这俩接口内部支持监听器ApplicationListener订阅特定类型的事件ApplicationEvent。

SimpleApplicationEventMulticaster作为真正事件发布者,其实是触发相应类型的事件监听器ApplicationListener执行特定的事件。

2.earlyApplicationEvents事件发布机制

earlyApplicationEvents字面意思是指需要及早触发的事件机制。这个“早”是指在IOC注册表中的bean实例化之前就需要触发的事件类型。

public abstract class AbstractApplicationContext{

	private Set<ApplicationEvent> earlyApplicationEvents;

	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			prepareRefresh();// 初始化变量 earlyApplicationEvents
			...
			prepareBeanFactory(beanFactory);
			postProcessBeanFactory(beanFactory);
			invokeBeanFactoryPostProcessors(beanFactory);
			registerBeanPostProcessors(beanFactory);
			...
			registerListeners();// 触发集合earlyApplicationEvents中所有事件
			finishBeanFactoryInitialization(beanFactory);
			finishRefresh();
		}
	}
	// earlyApplicationEvents集合中添加 需要及早触发的事件
	protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
		...
		if (this.earlyApplicationEvents != null) {
			 this.earlyApplicationEvents.add(applicationEvent);
		}else {
			 // 发布者添加事件后马上出发监听器执行
			 getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
		}
		...
	}
	
	protected void registerListeners() {
		// 获取SPI机制获取到的监听器
		for (ApplicationListener<?> listener : getApplicationListeners()) {
				// 将SPI机制获取到的监听器维护起来
			  getApplicationEventMulticaster().addApplicationListener(listener);
		}
		// 从IOC容器中获取ApplicationListener类型的事件监听器。此处步骤可以促使当前监听器提早实例化、初始化
		String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
		for (String listenerBeanName : listenerBeanNames) {
				// 将候选事件监听器维护起来
			  getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
		}
		// 当然对于自定义的事件类型必须显式添加到集合属性earlyApplicationEvents
		Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
		this.earlyApplicationEvents = null;
		if (earlyEventsToProcess != null) {
			for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
				// 从所有监听器中选出支持集合earlyEventsToProcess中事件类型的监听器,并直接触发监听机制执行
				getApplicationEventMulticaster().multicastEvent(earlyEvent);
			}
		}
	}
}

AbstractApplicationContext是ApplicationEventPublisher接口的子类,所以也是具有发布者功能的。在其内部事件的发布存在两种形式:

  1. 如果是在registerListeners之前就触发事件的发布,则这种类型的事件最终作为earlyApplicationEvents类型事件处理。
  2. 如果是在运行期触发事件的发布,则事件发布之时立即触发对应监听器监听事件。例如ApplicationEventPublisherAware实现的运行时发布者机制。

3.ApplicationEventPublisherAware

该类实现的事件发布机制其触发时机完全取决于web请求。具体触发流程参考AbstractApplicationContext集合earlyApplicationEvents中对应的事件类型执行流程。

class ApplicationContextAwareProcessor implements BeanPostProcessor {
		private void invokeAwareInterfaces(Object bean) {
				if (bean instanceof EnvironmentAware) {
					((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
				}
				...
				if (bean instanceof ApplicationEventPublisherAware) {//回调设置ApplicationEventPublisher
					((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
				}
				...
				if (bean instanceof ApplicationContextAware) {
					((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
				}
		}
}

ApplicationEventPublisher其实就是AbstractApplicationContext【本身就是发布者】。

4.ContextRefreshedEvent事件

Spring IOC容器就绪之后,框架将触发全部监听器处理ContextRefreshedEvent事件。

public abstract class AbstractApplicationContext{

	private Set<ApplicationEvent> earlyApplicationEvents;

	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			...
			prepareBeanFactory(beanFactory);
			postProcessBeanFactory(beanFactory);
			invokeBeanFactoryPostProcessors(beanFactory);
			registerBeanPostProcessors(beanFactory);
			...
			registerListeners();
			finishBeanFactoryInitialization(beanFactory);
			finishRefresh();//触发ContextRefreshedEvent事件
		}
	}
}

Dubbo中DubboDeployApplicationListener监听器就会处理该事件。

判断支持的事件类型

public abstract class AbstractApplicationEventMulticaster{

	private boolean supportsEvent(ConfigurableBeanFactory bf, String listenerBeanName, ResolvableType eventType) {
	
		Class<?> listenerType = bf.getType(listenerBeanName);
		// 如果监听器是GenericApplicationListener或者SmartApplicationListener类型,则支持全部的事件类型
		if (listenerType == null || GenericApplicationListener.class.isAssignableFrom(listenerType) ||
				SmartApplicationListener.class.isAssignableFrom(listenerType)) {
			return true;
		}
		// 如果监听器支持的事件类型与当前eventType事件类型一致或者当前事件类型eventType是监听器支持事件类型的子类
		if (!supportsEvent(listenerType, eventType)) {
			return false;
		}
		BeanDefinition bd = bf.getMergedBeanDefinition(listenerBeanName);
		//获取接口ApplicationListener的泛型之ApplicationEvent
		ResolvableType genericEventType = bd.getResolvableType().as(ApplicationListener.class).getGeneric();
		// 如果监听器监听的事件为基本事件类型ApplicationEvent或者ApplicationEvent其子类,则当前监听器处理全部事件类型
		return (genericEventType == ResolvableType.NONE || genericEventType.isAssignableFrom(eventType));
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值