SpringBoot启动过程之初始化器initializer和监听器listeners

参考https://my.oschina.net/xiaoqiyiye/blog/1624181 SpringBoot初始化器和监听器

        http://jinnianshilongnian.iteye.com/blog/1902886  Spring事件机制
        

Listener类图

SpringApplication构造的时候内部会调用一个private方法initialize:

public SpringApplication(Object... sources) {
initialize(sources); // sources目前是一个MyApplication的class对象
}
private void initialize(Object[] sources) {
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources)); // 把sources设置到SpringApplication的sources属性中,目前只是一个MyApplication类对象
}
this.webEnvironment = deduceWebEnvironment(); // 判断是否是web程序(javax.servlet.Servlet和org.springframework.web.context.ConfigurableWebApplicationContext都必须在类加载器中存在),并设置到webEnvironment属性中
// 从spring.factories文件中找出key为ApplicationContextInitializer的类并实例化后设置到SpringApplication的initializers属性中。这个过程也就是找出所有的应用程序初始化器
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
// 从spring.factories文件中找出key为ApplicationListener的类并实例化后设置到SpringApplication的listeners属性中。这个过程就是找出所有的应用程序事件监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 找出main类,这里是MyApplication类
this.mainApplicationClass = deduceMainApplicationClass();
}

ApplicationContextInitializer,应用程序初始化器,做一些初始化的工作:

public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
void initialize(C applicationContext);
}
类名
org.springframework.boot.context.config.DelegatingApplicationContextInitializer
org.springframework.boot.context.ContextIdApplicationContextInitializer
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer
org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer
org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer

功能描述:

  • DelegatingApplicationContextInitializer: 委派处理ApplicationContext初始化器,其需要委派处理的初始化器来自Spring环境中的context.initializer.classes属性,该属性可以使用逗号分隔多个初始化器。
  • ContextIdApplicationContextInitializer:为ApplicationContext设置id。根据以下的配置顺序来设置,spring.application.name、vcap.application.name、spring.config.name,如果环境配置中都没有这些配置,则默认使用“application”来表示,另外还会将profiles也加入到id中去。
  • ConfigurationWarningsApplicationContextInitializer:输出警告日志信息。
  • ServerPortInfoApplicationContextInitializer:添加一个EmbeddedServletContainerInitializedEvent事件监听,触发设置嵌入的WEB服务启动端口。通过属性local.[namespace].port来设置启动端口,其中namespace为ApplicationContext指定的命名空间,如果命名空间为空,则使用local.server.port属性来表示配置的端口。
  • SharedMetadataReaderFactoryContextInitializer:和Spring Boot共享CachingMetadataReaderFactory。
  • AutoConfigurationReportLoggingInitializer:添加一个通用的事件监听Springboot自动配置的报表日志输出。

在上面的初始化器分析中,我们可以看到,通过一些属性的读取可以设置Spring Boot启动过程中的一些参数。初始化器的功能可以在Spring Boot启动前对ApplicationContext进行一些自定义操作。初始化器是在准备上下文阶段调用的。

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
	context.getBeanFactory().registerSingleton("springApplicationArguments",
			applicationArguments);
	if (printedBanner != null) {
		context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
	}

	// Load the sources
	Set<Object> sources = getSources();
	Assert.notEmpty(sources, "Sources must not be empty");
	load(context, sources.toArray(new Object[sources.size()]));
	listeners.contextLoaded(context);
}

ApplicationListener,应用程序事件(ApplicationEvent)监听器: Spring事件机制见 https://blog.csdn.net/Bob_666/article/details/79714760

这里的应用程序事件(ApplicationEvent)有应用程序启动事件(ApplicationStartedEvent),失败事件(ApplicationFailedEvent),准备事件(ApplicationPreparedEvent)等。

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
void onApplicationEvent(E event);
}

应用程序事件监听器跟监听事件是绑定的。比如ConfigServerBootstrapApplicationListener只跟ApplicationEnvironmentPreparedEvent事件绑定,LiquibaseServiceLocatorApplicationListener只跟ApplicationStartedEvent事件绑定,LoggingApplicationListener跟所有事件绑定等。

key为ApplicationListener的有:

  1. org.springframework.boot.context.config.ConfigFileApplicationListener 重要(读取加载springboot配置文件) 转向环境和配置文件的加载
  2. org.springframework.boot.context.config.AnsiOutputApplicationListener(参数spring.output.ansi.enabled) 
    在springboot环境准备完成以后运行, 
    如果你的终端支持ANSI,设置彩色输出会让日志更具可读性。
  3. org.springframework.boot.logging.LoggingApplicationListener  根据配置初始化日志系统log
  4. org.springframework.boot.logging.ClasspathLoggingApplicationListener  程序启动时,讲classpath打印到debug日志,启动失败时classpath打印到info日志
  5. org.springframework.boot.autoconfigure.BackgroundPreinitializer
  6. org.springframework.boot.context.config.DelegatingApplicationListener(参数context.listener.classes) 
    把Listener转发给配置的这些class处理,这样可以支持外围代码不去写spring.factories中的org.springframework.context.ApplicationListener相关配置,保持springboot原来代码的稳定
  7. org.springframework.boot.builder.ParentContextCloserApplicationListener  容器关闭时发出通知,如果父容器关闭,那么自容器也一起关闭
  8. org.springframework.boot.context.FileEncodingApplicationListener(参数spring.mandatory-file-encoding) 
    在springboot环境准备完成以后运行,获取环境中的系统环境参数,检测当前系统环境的file.encoding和spring.mandatory-file-encoding设置的值是否一样,如果不一样则抛出异常 
    如果不配置spring.mandatory-file-encoding则不检查
  9. org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener                                                      (参数liquibase.servicelocator.ServiceLocator) 
    如果存在,则使用springboot相关的版本进行替代


SpringApplication的执行

public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		FailureAnalyzers analyzers = null;
		configureHeadlessProperty();
                //从Spirng.factories中获取key为SpringApplicationListeners的类(目前只有一个实现类EventPublishRunListener)并作为listenners属性的一个listener
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
...
}
private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
                //将SpringApplication对象传入,也就传入了SpringApplication的listeners属性
		return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
				SpringApplicationRunListener.class, types, this, args));
	}

分析run方法之前,先看一下SpringApplication中的一些事件和监听器概念。

首先是SpringApplicationRunListeners类和SpringApplicationRunListener类的介绍。

SpringApplicationRunListeners内部持有SpringApplicationRunListener集合和1个Log日志类。用于SpringApplicationRunListener监听器的批量执行。

SpringApplicationRunListener看名字也知道用于监听SpringApplication的run方法的执行。

它定义了5个步骤:

  1. starting(run方法执行的时候立马执行;对应事件的类型是ApplicationStartedEvent)
  2. environmentPrepared(ApplicationContext创建之前并且环境信息准备好的时候调用;对应事件的类型是ApplicationEnvironmentPreparedEvent)
  3. contextPrepared(ApplicationContext创建好并且在source加载之前调用一次;没有具体的对应事件)
  4. contextLoaded(ApplicationContext创建并加载之后并在refresh之前调用;对应事件的类型是ApplicationPreparedEvent)
  5. finished(run方法结束之前调用;对应事件的类型是ApplicationReadyEvent或ApplicationFailedEvent)

SpringApplicationRunListener目前只有一个实现类EventPublishingRunListener,它把监听的过程封装成了SpringApplicationEvent事件并让内部属性(intialMulticaster)ApplicationEventMulticaster接口的实现类SimpleApplicationEventMulticaster广播出去,广播出去的事件对象会被SpringApplication中的listeners属性进行处理。

所以说SpringApplicationRunListener和ApplicationListener之间的关系是通过ApplicationEventMulticaster广播出去的SpringApplicationEvent所联系起来的。

SpringApplicationRunListenners

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<SpringApplicationRunListener>(listeners);
	}

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

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

	public void contextPrepared(ConfigurableApplicationContext context) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.contextPrepared(context);
		}
	}

	public void contextLoaded(ConfigurableApplicationContext context) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.contextLoaded(context);
		}
	}

	public void finished(ConfigurableApplicationContext context, Throwable exception) {
		for (SpringApplicationRunListener listener : this.listeners) {
			callFinishedListener(listener, context, exception);
		}
	}

	private void callFinishedListener(SpringApplicationRunListener listener,
			ConfigurableApplicationContext context, Throwable exception) {
		try {
			listener.finished(context, exception);
		}
		catch (Throwable ex) {
			if (exception == null) {
				ReflectionUtils.rethrowRuntimeException(ex);
			}
			if (this.log.isDebugEnabled()) {
				this.log.error("Error handling failed", ex);
			}
			else {
				String message = ex.getMessage();
				message = (message == null ? "no error message" : message);
				this.log.warn("Error handling failed (" + message + ")");
			}
		}
	}

}

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
	@SuppressWarnings("deprecation")
	public void starting() {
		this.initialMulticaster
				.multicastEvent(new ApplicationStartedEvent(this.application, this.args));
	}

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

	@Override
	public void contextPrepared(ConfigurableApplicationContext context) {

	}

	@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));
	}

	@Override
	public void finished(ConfigurableApplicationContext context, Throwable exception) {
		SpringApplicationEvent event = getFinishedEvent(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);
				}
			}
			if (event instanceof ApplicationFailedEvent) {
				this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
			}
			this.initialMulticaster.multicastEvent(event);
		}
	}

	private SpringApplicationEvent getFinishedEvent(
			ConfigurableApplicationContext context, Throwable exception) {
		if (exception != null) {
			return new ApplicationFailedEvent(this.application, this.args, context,
					exception);
		}
		return new ApplicationReadyEvent(this.application, this.args, context);
	}

	private static class LoggingErrorHandler implements ErrorHandler {

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

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

	}

}

猜你喜欢

转载自blog.csdn.net/Bob_666/article/details/79715156