探索 SpringBoot (三) 启动流程详解(下)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35704236/article/details/84197459

探索 SpringBoot (三) 启动流程详解(下)

4 SpringBoot 运行阶段

接上文 我们看看 SpringBoot 到底干了啥吧。

  • 我们继续回到初始的地方 看看 run 方法
new SpringApplication(primarySources).run(args)

...

public ConfigurableApplicationContext run(String... args) {
        // 用于计时 不是重点 这里不深入讲解 有兴趣的小伙伴自己去读源码
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(
					SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
			prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass)
						.logStarted(getApplicationLog(), stopWatch);
			}
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}

		try {
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

4.1 Spring 应用运行监听者的加载和运行

SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();

...

listeners.started(context);

...

listeners.running(context);
  • 这里就是初始化了应用监听者。在应用的不同阶段 调用了不同的方法。我们看看 getRunListeners 干了啥
private SpringApplicationRunListeners getRunListeners(String[] args) {
	Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
	return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
			SpringApplicationRunListener.class, types, this, args));
}


class SpringApplicationRunListeners {

	private final Log log;

	private final List<SpringApplicationRunListener> listeners;

	SpringApplicationRunListeners(Log log,
			Collection<? extends SpringApplicationRunListener> listeners) {
		this.log = log;
		this.listeners = new ArrayList<>(listeners);
	}

	public void starting() {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.starting();
		}
	}

	public void environmentPrepared(ConfigurableEnvironment environment) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.environmentPrepared(environment);
		}
	}

	...
}
getSpringFactoriesInstances(SpringApplicationRunListener.class, ...)

这个方法上面讲过了 就是加载 spring.factory 下面的实现类,目前

key 为 SpringApplicationRunListener 的实现类就 一个 EventPublishingRunListener

我们 大概看下这个东西长啥样 

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()) {
			this.initialMulticaster.addApplicationListener(listener);
		}
	}

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

	@Override
	public void starting() {
		this.initialMulticaster.multicastEvent(
				new ApplicationStartingEvent(this.application, this.args));
	}

	@Override
	public void environmentPrepared(ConfigurableEnvironment environment) {
		this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(
				this.application, this.args, environment));
	}

...

反正就记住 通过 getRunListeners 方法 初始化了一个监听者 EventPublishingRunListener,当调用 listeners.starting(); 的时候相当于调用了 EventPublishingRunListener 的 

@Override
public void starting() {
	this.initialMulticaster.multicastEvent(
			new ApplicationStartingEvent(this.application, this.args));
}
	
这个方法, spring 这样做也是便于扩展。
  • 我们接着往下看看之后发生了什么

  • initialMulticaster 其实就是一个广播者,负责广播事件。 我们看看 multicastEvent 方法

@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));
	for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
		Executor executor = getTaskExecutor();
		if (executor != null) {
			executor.execute(() -> invokeListener(listener, event));
		}
		else {
			invokeListener(listener, event);
		}
	}
}

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({"unchecked", "rawtypes"})
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.isDebugEnabled()) {
				logger.debug("Non-matching event type for listener: " + listener, ex);
			}
		}
		else {
			throw ex;
		}
	}
}


最终调用到这个方法上面了,

listener.onApplicationEvent(event);

你肯定好奇这个 listener 是什么,其实就是我们上一篇加载的 ApplicationListener 的实现类,去执行 listener 的方法。

我们梳理一下:

1 SpringApplicationRunListeners listeners = getRunListeners(args); 加载监听者 EventPublishingRunListener

2 EventPublishingRunListener 内部维护一个广播者,在构造的时候从上下文获取监听者(ApplicationListener 的实现类) 并且放入广播列表 

3 当 spring 运行到对应生命周期的时候 调用对应方法,比如 listeners.starting(); 经过  EventPublishingRunListener 内部的广播者 最终调用到 listener.onApplicationEvent(event); (ApplicationListener 的实现类) 

4 最后 listener 不同的实现类 进行不同的时间处理逻辑

好了 关于 spring 的 事件/监听器 模型就讲完了。

4.2 解析输入参数 构建运行环境

// 这里就是讲 run 方法传入的参数 以 key-value 的形式解析 没有太大的难度
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);

// 这里的作用就是根据输入参数 解析出那些事可用的配置,监听者对应事件的通知
ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
					
...

private ConfigurableEnvironment prepareEnvironment(
			SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
	// Create and configure the environment
	ConfigurableEnvironment environment = getOrCreateEnvironment();
	configureEnvironment(environment, applicationArguments.getSourceArgs());
	listeners.environmentPrepared(environment);
	bindToSpringApplication(environment);
	if (!this.isCustomEnvironment) {
		environment = new EnvironmentConverter(getClassLoader())
				.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
	}
	ConfigurationPropertySources.attach(environment);
	return environment;
}

4.3 上下文创建

因为这一块内容比较多 也比较难 所以楼主也就简单介绍一下

context = createApplicationContext();

...

prepareContext(context, environment, listeners, applicationArguments,
		printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);

4.3.1 上下文的创建 createApplicationContext

protected ConfigurableApplicationContext createApplicationContext() {
	Class<?> contextClass = this.applicationContextClass;
	if (contextClass == null) {
		try {
			switch (this.webApplicationType) {
			case SERVLET:
				contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
				break;
			case REACTIVE:
				contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
				break;
			default:
				contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
			}
		}
		catch (ClassNotFoundException ex) {
			throw new IllegalStateException(
					"Unable create a default ApplicationContext, "
							+ "please specify an ApplicationContextClass",
					ex);
		}
	}
	return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
  • 这里就是根据上一篇中推断出来的 webApplicationType ,加载对应的类,并且实例化上下文对象,如果是我们场景的 servlet 容器的话 实现类是这个
org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext

4.3.2 上下文环境预处理 prepareContext

prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);

private void prepareContext(ConfigurableApplicationContext context,
			ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments, Banner printedBanner) {
	context.setEnvironment(environment);
	postProcessApplicationContext(context);
	applyInitializers(context);
	listeners.contextPrepared(context);
	if (this.logStartupInfo) {
		logStartupInfo(context.getParent() == null);
		logStartupProfileInfo(context);
	}
	// Add boot specific singleton beans
	ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
	beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
	if (printedBanner != null) {
		beanFactory.registerSingleton("springBootBanner", printedBanner);
	}
	if (beanFactory instanceof DefaultListableBeanFactory) {
		((DefaultListableBeanFactory) beanFactory)
				.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
	}
	// Load the sources
	Set<Object> sources = getAllSources();
	Assert.notEmpty(sources, "Sources must not be empty");
	load(context, sources.toArray(new Object[0]));
	listeners.contextLoaded(context);
}

主要看看这个方法, 这个方法加载了上下文

load(context, sources.toArray(new Object[0]));

protected void load(ApplicationContext context, Object[] sources) {
	if (logger.isDebugEnabled()) {
		logger.debug(
				"Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
	}
	BeanDefinitionLoader loader = createBeanDefinitionLoader(
			getBeanDefinitionRegistry(context), sources);
	if (this.beanNameGenerator != null) {
		loader.setBeanNameGenerator(this.beanNameGenerator);
	}
	if (this.resourceLoader != null) {
		loader.setResourceLoader(this.resourceLoader);
	}
	if (this.environment != null) {
		loader.setEnvironment(this.environment);
	}
	loader.load();
}

...

private BeanDefinitionRegistry getBeanDefinitionRegistry(ApplicationContext context) {
	if (context instanceof BeanDefinitionRegistry) {
		return (BeanDefinitionRegistry) context;
	}
	if (context instanceof AbstractApplicationContext) {
		return (BeanDefinitionRegistry) ((AbstractApplicationContext) context)
				.getBeanFactory();
	}
	throw new IllegalStateException("Could not locate BeanDefinitionRegistry");
}
...

BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
	Assert.notNull(registry, "Registry must not be null");
	Assert.notEmpty(sources, "Sources must not be empty");
	this.sources = sources;
	this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
	this.xmlReader = new XmlBeanDefinitionReader(registry);
	if (isGroovyPresent()) {
		this.groovyReader = new GroovyBeanDefinitionReader(registry);
	}
	this.scanner = new ClassPathBeanDefinitionScanner(registry);
	this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
}

这里根据传入的注册信息用多种方式去加载 

4.3.3 刷新上下文

refreshContext(context);

...

private void refreshContext(ConfigurableApplicationContext context) {
		refresh(context);
	if (this.registerShutdownHook) {
		try {
			context.registerShutdownHook();
		}
		catch (AccessControlException ex) {
			// Not allowed in some environments.
		}
	}
}

...

protected void refresh(ApplicationContext applicationContext) {
	Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
	((AbstractApplicationContext) applicationContext).refresh();
}

...

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
		// Prepare this context for refreshing.
		prepareRefresh();

		// Tell the subclass to refresh the internal bean factory.
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

		// Prepare the bean factory for use in this context.
		prepareBeanFactory(beanFactory);

		try {
			// Allows post-processing of the bean factory in context subclasses.
			postProcessBeanFactory(beanFactory);

			// Invoke factory processors registered as beans in the context.
			invokeBeanFactoryPostProcessors(beanFactory);

			// Register bean processors that intercept bean creation.
			registerBeanPostProcessors(beanFactory);

			// Initialize message source for this context.
			initMessageSource();

			// Initialize event multicaster for this context.
			initApplicationEventMulticaster();

			// Initialize other special beans in specific context subclasses.
			onRefresh();

			// Check for listener beans and register them.
			registerListeners();

			// Instantiate all remaining (non-lazy-init) singletons.
			finishBeanFactoryInitialization(beanFactory);

			// Last step: publish corresponding event.
			finishRefresh();
		}

		catch (BeansException ex) {
			if (logger.isWarnEnabled()) {
				logger.warn("Exception encountered during context initialization - " +
						"cancelling refresh attempt: " + ex);
			}

			// Destroy already created singletons to avoid dangling resources.
			destroyBeans();

			// Reset 'active' flag.
			cancelRefresh(ex);

			// Propagate exception to caller.
			throw ex;
		}

		finally {
			// Reset common introspection caches in Spring's core, since we
			// might not ever need metadata for singleton beans anymore...
			resetCommonCaches();
		}
	}
}


这里就是容器 和 容器里面的 bean 的各种操作和处理了,楼主水平有限,各位看官自己慢慢研究吧。。。

4.3.4 刷新上下文之后

afterRefresh(context, applicationArguments);

...

protected void afterRefresh(ConfigurableApplicationContext context,
			ApplicationArguments args) {
}

  • 你没有看错 就是一片空白,这个估计就是 spring 留给我们自己去实现的。

5 总结

好不容易写完了,但是感觉意犹未尽,很多东西都没有说清楚,像 内置容器的启动, ioc 过程, aop 过程。也是楼主水平有限,这里就相当于抛砖引玉吧。如果发现文章中的错误欢迎指正哈。

猜你喜欢

转载自blog.csdn.net/qq_35704236/article/details/84197459