观察者模式下的SpringBoot启动过程

原创
04/26 23:19
阅读数 155

观察者模式

一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。 观察者模式有非常多的应用场景,其中包含消息订阅、事件驱动等,本文会带大家一起探讨观察者模式的基础应用和Spring中的事件驱动机制的使用。

一、SpringBoot基于EventListener和EventObject实现的观察者模式

1、JDK中的EventObject

package java.util;

/**
 * @since JDK1.1
 */

public class EventObject implements java.io.Serializable {

    private static final long serialVersionUID = 5516075349620653480L;

    /**
     * 事件发生对象
     */
    protected transient Object  source;

    /**
     * 构造器
     */
    public EventObject(Object source) {
        if (source == null)
            throw new IllegalArgumentException("null source");

        this.source = source;
    }

    public Object getSource() {
        return source;
    }

    public String toString() {
        return getClass().getName() + "[source=" + source + "]";
    }
}

2、Spring中的ApplicationEvent

package org.springframework.context;

import java.util.EventObject;

/**
 * ApplicationEvent 抽象类,必须要实现
 */
public abstract class ApplicationEvent extends EventObject {

	/**序列号*/
	private static final long serialVersionUID = 7099057708183571937L;

	/** 发生时间戳 */
	private final long timestamp;


	/**
	 * 构造器
	 */
	public ApplicationEvent(Object source) {
		super(source);
		this.timestamp = System.currentTimeMillis();
	}
	
	public final long getTimestamp() {
		return this.timestamp;
	}

}

3、SpringBoot的抽象SpringApplicatioinEvent 加了个数组参数

/**
 * SpringBoot的抽象事件,截至2.0版本有7个实现类,下面具体会讲
 */
public abstract class SpringApplicationEvent extends ApplicationEvent {

	private final String[] args;

	public SpringApplicationEvent(SpringApplication application, String[] args) {
		super(application);
		this.args = args;
	}

	public SpringApplication getSpringApplication() {
		return (SpringApplication) getSource();
	}

	public final String[] getArgs() {
		return this.args;
	}

}

4、SpringBoot中的事件驱动中的核心Run Listeners

/**
 * SpringApplicationRunListener是SpringBoot中的核心接口,
 * 在第一步new SpringApplication的时候已经被加载,启动顺序也排第一
 * 用于发布事件,具体实现为EventPublishingRunListener
 * 父类7个方法分别发布SpringBoot启动过程中7大事件,子类实现中都调用了ApplicationEventMulticaster.multicastEvent(ApplicationEvent e)
 */
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {

	private final SpringApplication application;

	private final String[] args;

	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()) {
			// 将所有的listener添加到多播器中
			this.initialMulticaster.addApplicationListener(listener);
		}
	}

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

	/**
	*  用于发布 ApplicationStartingEvent, 在SpringBoot工程启动的时候
	 */
	@Override
	public void starting() {
		this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
	}

	/**
	 * 一旦Environment环境准备好就会执行,用于发布 ApplicationEnvironmentPreparedEvent
	 */
	@Override
	public void environmentPrepared(ConfigurableEnvironment environment) {
		this.initialMulticaster
				.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
	}

	/**
	* 一旦ApplicationContext被初始化就会执行,用于发布ApplicationContextInitializedEvent
	 */
	@Override
	public void contextPrepared(ConfigurableApplicationContext context) {
		this.initialMulticaster
				.multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
	}

	/**
	 * 在ApplicationContext被准备好以后但是没有调用refresh之前调用,用于发布ApplicationPreparedEvent
	 */
	@Override
	public void contextLoaded(ConfigurableApplicationContext context) {
		for (ApplicationListener<?> listener : this.application.getListeners()) {
			if (listener instanceof ApplicationContextAware) {
				((ApplicationContextAware) listener).setApplicationContext(context);
			}
			context.addApplicationListener(listener);
		}
		this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
	}

	/**
	* ApplicationContext.refresh()方法被调用以后执行,此时CommandLineRunner和ApplicationRunner还没有被调用
	* 用于发布ApplicationStartedEvent
	 */
	@Override
	public void started(ConfigurableApplicationContext context) {
		context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
		AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);
	}
	
	/**
	 * 调用所有的CommandLineRunner和ApplicationRunner后,SpringApplicaton.run()方法接近完成,程序运行成功
	 * 用于发布ApplicationReadyEvent
	 */
	@Override
	public void running(ConfigurableApplicationContext context) {
		context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
		AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);
	}
	
	/**
	* 如果发生失败则调用,用于发布ApplicationFailedEvent 通知应用程序的监听者程序启动失败的消息
	 */
	@Override
	public void failed(ConfigurableApplicationContext context, Throwable exception) {
		ApplicationFailedEvent event = new ApplicationFailedEvent(this.application, this.args, context, exception);
		if (context != null && context.isActive()) {
			// Listeners have been registered to the application context so we should
			// use it at this point if we can
			context.publishEvent(event);
		}
		else {
			// An inactive context may not have a multicaster so we use our multicaster to
			// call all of the context's listeners instead
			if (context instanceof AbstractApplicationContext) {
				for (ApplicationListener<?> listener : ((AbstractApplicationContext) context)
						.getApplicationListeners()) {
					this.initialMulticaster.addApplicationListener(listener);
				}
			}
			this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
			this.initialMulticaster.multicastEvent(event);
		}
	}

	private static class LoggingErrorHandler implements ErrorHandler {

		private static final Log logger = LogFactory.getLog(EventPublishingRunListener.class);

		@Override
		public void handleError(Throwable throwable) {
			logger.warn("Error calling ApplicationEventListener", throwable);
		}

	}

}

5、SpringBoot中的多播器SimpleApplicationEventMulticaster

/**
 * ApplicationEventMulticaster的简单实现
 * 将所有事件广播给所有注册的侦听器,让它自行处理
 * EventPublishingRunListener发布每个事件的时候都会调用multicastEvent(ApplicationEvent)进行发布
 * 在此方法中会调用所有的Listeners
 */
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {

	@Nullable
	private Executor taskExecutor;

	@Nullable
	private ErrorHandler errorHandler;

	public SimpleApplicationEventMulticaster() {
	}
	
	public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {
		setBeanFactory(beanFactory);
	}
	
	public void setTaskExecutor(@Nullable Executor taskExecutor) {
		this.taskExecutor = taskExecutor;
	}
	
	@Nullable
	protected Executor getTaskExecutor() {
		return this.taskExecutor;
	}

	public void setErrorHandler(@Nullable ErrorHandler errorHandler) {
		this.errorHandler = errorHandler;
	}

	@Nullable
	protected ErrorHandler getErrorHandler() {
		return this.errorHandler;
	}


	@Override
	public void multicastEvent(ApplicationEvent event) {
		multicastEvent(event, resolveDefaultEventType(event));
	}

	@Override
	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
		Executor executor = getTaskExecutor();
		for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
			if (executor != null) {
				executor.execute(() -> invokeListener(listener, event));
			}
			else {
				invokeListener(listener, event);
			}
		}
	}

	private ResolvableType resolveDefaultEventType(ApplicationEvent event) {
		return ResolvableType.forInstance(event);
	}

	/**
	* 通知SpringApplicationListener 调用的onApplicationEvent
	 */
	protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
		ErrorHandler errorHandler = getErrorHandler();
		if (errorHandler != null) {
			try {
				doInvokeListener(listener, event);
			}
			catch (Throwable err) {
				errorHandler.handleError(err);
			}
		}
		else {
			doInvokeListener(listener, event);
		}
	}

	@SuppressWarnings({"rawtypes", "unchecked"})
	private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
		try {
			listener.onApplicationEvent(event);
		}
		catch (ClassCastException ex) {
			String msg = ex.getMessage();
			if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
				// Possibly a lambda-defined listener which we could not resolve the generic event type for
				// -> let's suppress the exception and just log a debug message.
				Log logger = LogFactory.getLog(getClass());
				if (logger.isTraceEnabled()) {
					logger.trace("Non-matching event type for listener: " + listener, ex);
				}
			}
			else {
				throw ex;
			}
		}
	}

	private boolean matchesClassCastMessage(String classCastMessage, Class<?> eventClass) {
		// On Java 8, the message starts with the class name: "java.lang.String cannot be cast..."
		if (classCastMessage.startsWith(eventClass.getName())) {
			return true;
		}
		// On Java 11, the message starts with "class ..." a.k.a. Class.toString()
		if (classCastMessage.startsWith(eventClass.toString())) {
			return true;
		}
		// On Java 9, the message used to contain the module name: "java.base/java.lang.String cannot be cast..."
		int moduleSeparatorIndex = classCastMessage.indexOf('/');
		if (moduleSeparatorIndex != -1 && classCastMessage.startsWith(eventClass.getName(), moduleSeparatorIndex + 1)) {
			return true;
		}
		// Assuming an unrelated class cast failure...
		return false;
	}

}

二、SpringBoot基于EventListener和EventObject的事件驱动模型

以java.util.EventObject为基础,抽象实现出ApplicationEvent, SpringBoot在此基础上,又实现出SpringApplicationEvent抽象类,最后才实现出SpringBoot中的七大事件,代表整个SpringBoot启动的所有生命周期

1. ApplicationStartingEvent

SpringApplication.run() 方法中的第一个状态,从spring.factories文件中加载完成SpringApplicationRunLinstener,就立即调用listener.starting()方法发布此事件,

  1. 代表SpringBoot工程开始启动。在此之前SpringApplication实例已经初始化完成,
  2. 所有配置在spring.factories中的ApplicationListener,也就是SpringApplicationEvent的监听器也已经被加载。
  3. 所有配置在spring.factories中的ApplicationContextInitializer被加载到SpringApplication中
  4. StopWatch启动
  5. SpringApplicationRunLinstener的唯一实现EventPublishingRunListener被加载

2. ApplicationEnvironmentPreparedEvent

在SpringApplication启动且Environment对象首先可用于检查和修改时发布的事件。

  1. SpringBoot实例化了ConfigurableEnvironment对象
  2. 初始化了spring.profilesmain(String ... args)方法传进来的args
  3. 代表Environment环境对象准备完成
  4. 然后通过调用listeners.environmentPrepared(environment)方法发布了此事件
  5. 接下来会调用Banner打印SpringBoot的彩蛋。

3. ApplicationContextInitializedEvent

在启动SpringApplication并准备好ApplicationContext并调用ApplicationContextInitializers之前(但未加载任何bean定义之前)发布的事件。

  1. 根据webApplicationType创建了一个AnnotationConfigServletWebServerApplicationContext并给其设置Environment为之前创建的ConfigurableEnvironment对象,创建了DefaultListableBeanFactory
  2. 加载所有配置在spring.factories文件中的SpringBootExceptionReporter
  3. 调用了spring.factories文件中定义并且已经读取到SpringApplication中的ApplicationContextInitializer
  4. 调用listeners.contextPrepared(context)发布了此事件

4. ApplicationPreparedEvent

在SpringApplication启动且ApplicationContext已准备齐全但未刷新时发布的事件。

  1. 打印启动的profile日志
  2. 添加了特殊的单例bean到boot(springApplicationArguments和springBootBanner)
  3. 设置BeanFactory不允许重写Bean定义信息
  4. 创建了BeanDefinitionLoader并且将SpringBoot工程启动类设置给了BeanDefinitionLoader
  5. 调用listeners.contextLoaded(context)发布了此事件

5. ApplicationStartedEvent

刷新应用程序上下文后,但在调用任何ApplicationRunner应用程序}和CommandLineRunner命令行运行程序之前,都会发布事件。

  1. 调用了AbstractApplicationContext.refresh()方法。此方法是Spring启动的核心方法,SpringBoot中有很多扩展实现方法。

    • prepareRefresh()准备上下文,刷新前的工作
    • ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory()刷新内部BeanFactory
    • prepareBeanFactory(beanFactory)给BeanFactory设置各种属性
    • postProcessBeanFactory(beanFactory);允许在上下文子类中对bean工厂进行后处理
    • invokeBeanFactoryPostProcessors(beanFactory)调用在上下文中注册为bean的BeanFactoryPostProcessor,此环节中调用了其实现类ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry()方法,所有在spring.factories中的AutoConfiguration都在此环节被初始化
    • registerBeanPostProcessors(beanFactory)注册所有的BeanPostProcessor
    • initMessageSource()初始化messageSource
    • initApplicationEventMulticaster()初始化Spring监听者模式的多播器SimpleApplicationEventMulticaster(此多播器和EventPublishRunListener中的多播器是两个不同对象,此为BeanFactory中的单例对象)
    • onRefresh()在特定上下文子类中初始化其他特殊bean,此过程中调用super.refresh()方法,创建了WebServer,也就是Tomcat容器,但是此时Tomcat只是被注册到BeanFactory中的一个单例对象,并没有被启动。
    • registerListeners()将所有的Listeners监听器注册到BeanFactory中的多播器SimpleApplicationEventMulticaster
    • finishBeanFactoryInitialization()完成此上下文的bean工厂的初始化,初始化所有剩余的单例bean,比如我们自己创建的Service和Dao等其他的Bean都会在这个阶段初始化
    • 完成上下文刷新,启动之前创建好的Tomcat。
  2. 注册ShutDownHook挂钩,用于当前jvm结束进程的时候能优雅的结束此程序

6. ApplicationReadyEvent

表明该应用程序已准备就绪,可以处理请求。事件的来源是SpringApplication本身,但是请注意不要修改其内部状态,因为所有初始化步骤到那时都已完成。

  1. 此阶段就是调用了callRuners(),包含所有的ApplicationRunnerCommandLineRunner

7. ApplicationFailedEvent

SpringApplication启动失败时发布的事件。

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部