您的位置:首页 > 编程语言 > Java开发

SpringBoot启动过程源码解析(二)--------------- listener.starting及监听模式的实现

2019-03-11 23:30 671 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/qq_42345486/article/details/88411562

上一篇讲了SpringBoot启动过程中, SpringApplication实例化之后,现在正式进入到 SpringApplication.run 方法中,看一看启动过程中,SpringBoot到底做了些什么。 

本篇博客先讲到 listener.starting() , 通过这个方式 讲一讲 监听器设计模式。

先看,Run方法

[code]public ConfigurableApplicationContext run(String... args) {
// 监控启动过程中耗费时间
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
// 输出启动过程中的异常
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
// 设置 java.awt.headless , 具体情况另行查阅
configureHeadlessProperty();
// 加载 SpringApplicationRunListener
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;
}

先看一个重要的方法 : getRunListeners(args) , 这个方法是从 META-INF/spring.factories文件中加载 SpringApplicationRunListener实现类。目前SpringApplicationRunListener 唯一实现类为EventPublishingRunListener。

[code]private SpringApplicationRunListeners getRunListeners(String[] args) {
// 将命令行参数继续往下传递.通过 class 类型加载,根据实例化工厂加载所需类
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}

通过实例化工厂, SpringApplicationRunListener.class 类型,再META-INF/spring.factories文件下加载类名,实例化EventPublishingRunListener对象。 加载过程细节已在上一篇种讲述,不再赘述。

接下来就是重要的事件发布方法。 listeners.staring()

SpringApplicationRunListeners维护着一个List<SpringApplicationRunListener>集合,方便统一调用RunListener starting()方法。

我们可以自定义一个Listener 实现 SpringApplicationRunListener接口,并注册到META-INF/spring.factories 自己实现启动过程的事件逻辑。EventPublishingRunListener 作为官方唯一实现类。

EventPublishingRunListener种持有SimleApplicationEventMulticaster对象,用于广播发布事件。

[code]@Override
public void starting() {
// 以广播形式发布 ApplicationStaringEvent事件
this.initialMulticaster.multicastEvent(
new ApplicationStartingEvent(this.application, this.args));
}

 

[code]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);
}
}
}

  在发布事件种有重要方法, getAppllicationListeners()

[code]protected Collection<ApplicationListener<?>> getApplicationListeners(
ApplicationEvent event, ResolvableType eventType) {

Object source = event.getSource();
Class<?> sourceType = (source != null ? source.getClass() : null);
// 内部类缓存储存 事件类型
ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);

// Quick check for existing entry on ConcurrentHashMap...
// 先检查缓存中是否存在
ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
}

if (this.beanClassLoader == null ||
(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
// Fully synchronized building and caching of a ListenerRetriever
synchronized (this.retrievalMutex) {
retriever = this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
}
retriever = new ListenerRetriever(true);
Collection<ApplicationListener<?>> listeners =
retrieveApplicationListeners(eventType, sourceType, retriever);
this.retrieverCache.put(cacheKey, retriever);
return listeners;
}
}
else {
// No ListenerRetriever caching -> no synchronization necessary
return retrieveApplicationListeners(eventType, sourceType, null);
}
}

先存缓存中判断是否存在 监听器, 如何没有,调用 retrieveApplicationListeners 方法获取。

 在实例化EventPublishingRunListener 构造函数中,已将SpringApplication 构造函数中加载的10个Listeners 放入ListenerRriever中,并删除了缓存中 retrieveCache中的数据。

[code]private Collection<ApplicationListener<?>> retrieveApplicationListeners(
ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable ListenerRetriever retriever) {

List<ApplicationListener<?>> allListeners = new ArrayList<>();
Set<ApplicationListener<?>> listeners;
Set<String> listenerBeans;
synchronized (this.retrievalMutex) {
listeners = n
3ff7
ew LinkedHashSet<>(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
}
for (ApplicationListener<?> listener : listeners) {
if (supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
retriever.applicationListeners.add(listener);
}
allListeners.add(listener);
}
}
if (!listenerBeans.isEmpty()) {
BeanFactory beanFactory = getBeanFactory();
for (String listenerBeanName : listenerBeans) {
try {
Class<?> listenerType = beanFactory.getType(listenerBeanName);
if (listenerType == null || supportsEvent(listenerType, eventType)) {
ApplicationListener<?> listener =
beanFactory.getBean(listenerBeanName, ApplicationListener.class);
if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
if (beanFactory.isSingleton(listenerBeanName)) {
retriever.applicationListeners.add(listener);
}
else {
retriever.applicationListenerBeans.add(listenerBeanName);
}
}
allListeners.add(listener);
}
}
}
catch (NoSuchBeanDefinitionException ex) {
// Singleton listener instance (without backing bean definition) disappeared -
// probably in the middle of the destruction phase
}
}
}

通过 ApplicationStartingEvent事件类型,过滤出对一个事件的 监听器,并发布事件。

supportsEvent()方法中。用到适配器设计模式,传入事件类型与监听器进行判断。

[code]protected boolean supportsEvent(
ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {

GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}

筛选中出监听器后,调用 invokeListener方法通知监听器,监听器做出相应动作。

 

浅谈监听器模式  : 

监听器模式的三要素:  事件源,事件,监听器 

事件源 : 需要被监听器的对象。

事件: 对事件源的封装。

监听器: 被监听对象改变后,做出相应动作。

 

在启动过程中 ,

SpringApplicaton 就是事件源

ApplicationStartingEvent 是事件 

ApplicationListeners 为监听器 

SpringApplicationRunListener 可以理解成 ListenerManager

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: