上一篇中我们主要看了SpringApplication的初始化,接下去几篇我们着重看下run方法
<---------
public ConfigurableApplicationContext run(String... args) {
// 计时工具
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
// 创建一个DefaultApplicationArguments对象,它持有着args参数,就是main函数传进来的参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
Banner printedBanner = printBanner(environment);
// 创建SpringBoot上下文
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
----->
以上是run方法的全部,大致归纳下就是:
1.初始化StopWatch,调用其start方法开始计时.
2.调用configureHeadlessProperty设置系统属性java.awt.headless,这里设置为true,表示运行在服务器端,在没有显示器和鼠标键盘的模式下工作,模拟输入输出设备功能
3.调用SpringApplicationRunListeners#starting
4.创建一个DefaultApplicationArguments对象,它持有着args参数,就是main函数传进来的参数.调用prepareEnvironment方法.
5.打印banner
6.创建SpringBoot上下文
7.初始化FailureAnalyzers
8.调用prepareContext
9.调用AbstractApplicationContext#refresh方法,并注册钩子
10.在容器完成刷新后,依次调用注册的Runners
11.调用SpringApplicationRunListeners#finished
12.停止计时
---->
1.2跳过
3. SpringApplicationRunListeners listeners = getRunListeners(args);这行代码我们深入分析
---->
Class>[] types = new Class[]{SpringApplication.class, String[].class}; return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)); 重点在第三句代码,我们发现这行代码和第一篇中的inilizer方法很类似,只是现在传入的clazz是SpringApplicationRunListener,在jar包中的META-INF/spring-factories文件中以SpringApplicationRunListener为key的value只有一个
是EventPublishingRunListner。我们深入
SpringApplicationRunListeners类发现
class SpringApplicationRunListeners { private final Log log; private final Listlisteners;只有两个属性,一个是日志相关,还有一个是SpringApplicationRunListener的集合,而实际上listeners只有一个元素
在springboot中 SpringApplicationRunListener主要支持四种事件的监听,我们通过源码来看
SpringApplicationRunListener接口定义的方法有
public interface SpringApplicationRunListener { void started(); void environmentPrepared(ConfigurableEnvironment var1); void contextPrepared(ConfigurableApplicationContext var1); void contextLoaded(ConfigurableApplicationContext var1); void finished(ConfigurableApplicationContext var1, Throwable var2); }
springboot中继承SpringApplicationRunListener的实现类只有EventPublishingRunListener
EventPublishingRunListener中
public void started() { this.initialMulticaster.multicastEvent(new ApplicationStartedEvent(this.application, this.args)); }
这里可以看到这里发布了一个事件ApplicationStartedEvent,而这个started方法是在run方法中的这个位置实现的
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
// 创建一个DefaultApplicationArguments对象,它持有着args参数,就是main函数传进来的参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
从名字也能看出这是springboot容器启动事件
然后我们发现在
ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);
这句代码中进入之后
---->
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { 。。。。。 listeners.environmentPrepared(environment);//这句话跟踪到
。。。。。。
EventPublishingRunListener的environmentPrepared方法可以看到ApplicationEnvironmentPreparedEvent }
---->
我们还可以在
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);以及
listeners.finished(context, (Throwable)null);两句代码中发现还有两个事件
ApplicationPreparedEvent
ApplicationFailedEvent
总结一下就是springboot在容器初始化过程中会初始化
SpringApplicationRunListeners,其中的SpringApplicationRunListener集合只包含了一个EventPublishingRunListener
这个listener会分发四种事件,分别是
ApplicationStartedEvent
ApplicationEnvironmentPreparedEvent
ApplicationPreparedEvent
ApplicationFailedEvent
。
这里我们按照分析run方法的顺序,只分析ApplicationStartedEvent事件
---------------------------------------------------->
listeners.starting();
--------->
public void started() { Iterator var1 = this.listeners.iterator(); while(var1.hasNext()) { SpringApplicationRunListener listener = (SpringApplicationRunListener)var1.next(); listener.started(); } }这里会依次遍历SpringApplicationRunListeners中的SpringApplicationRunListener集合,前面我们已经说过,这个集合中只有一个元素,所以就是执行EventPublishingRunListner中的started方法,我们跟入
----->
this.initialMulticaster.multicastEvent(new ApplicationStartedEvent(this.application, this.args));
initialMulticaster是一个时间广播器,具体我们在后续的refresh方法中详解,现在就理解成发布事件的东西
跟踪进入
--------> public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) { 。。。。。。。 for (final ApplicationListener> listener : getApplicationListeners(event, type)) { 。。。。。。
首先我们分析 getApplicationListeners这句话
------->
protected Collection
Object source = event.getSource();
Class> sourceType = (source != null ? source.getClass() : null);
ListenerCacheKey cacheKey = new ListenerCacheKey(event.getClass(), 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
retrieveApplicationListeners(event, sourceType, retriever);
this.retrieverCache.put(cacheKey, retriever);
return listeners;
}
}
else {
// No ListenerRetriever caching -> no synchronization necessary
return retrieveApplicationListeners(event, sourceType, null);
}
}
代码比较长,简要的概括下就是
该方法首先构建ListenerCacheKey,然后查询缓存中是否有的话,直接返回.否则调用retrieveApplicationListeners方法.如果
this.beanClassLoader == null ||
(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader))) 为真的话,则调用retrieveApplicationListeners方法时会进行加锁.并将方法的返回值加入缓存.一般都会放入缓存的.
这里要跟进一下这块代码
retrieveApplicationListeners方法,代码如下:
private Collection
ResolvableType eventType, Class> sourceType, ListenerRetriever retriever) {
LinkedList
Set
Set
synchronized (this.retrievalMutex) {
listeners = new LinkedHashSet
listenerBeans = new LinkedHashSet
}
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) {
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
}
}
}
AnnotationAwareOrderComparator.sort(allListeners);
return allListeners;
}
简要概括下
处理逻辑如下:
初始化allListeners, listeners,listenerBeans,对于当前场景来说. listeners 中的元素如下:
org.springframework.boot.context.config.ConfigFileApplicationListener,
org.springframework.boot.context.config.AnsiOutputApplicationListener,
org.springframework.boot.logging.LoggingApplicationListener,
org.springframework.boot.logging.ClasspathLoggingApplicationListener,
org.springframework.boot.autoconfigure.BackgroundPreinitializer,
org.springframework.boot.context.config.DelegatingApplicationListener,
org.springframework.boot.builder.ParentContextCloserApplicationListener,
org.springframework.boot.ClearCachesApplicationListener,
org.springframework.boot.context.FileEncodingApplicationListener,
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
listenerBeans中的元素为空.
遍历listeners, listenerBeans 如果监听器是否支持指定的事件则加入到allListeners.
排序
对于当前场景ApplicationStartedEvent支持的listeners如下:
----最后一个listener是我自己定义的
然后我们回到
multicastEvent方法
for (final ApplicationListener> listener : getApplicationListeners(event, type)) { Executor executor = getTaskExecutor(); if (executor != null) { executor.execute(new Runnable() { @Override public void run() { invokeListener(listener, event); } }); } else { invokeListener(listener, event); } } }
接下去就是遍历之前返回的几个linstener,这里根据有没有传入excutor来判断要不要进行异步操作,
我们进入 invokeListener(listener, event)方法
protected void invokeListener(ApplicationListener listener, ApplicationEvent event) { 。。。。。。 if (errorHandler != null) { try { listener.onApplicationEvent(event); } 。。。。。。。。
这里面就是直接调用了listener的onApplicationEvent(event)方法所以我们只要分析这几个listener的onApplicationEvent(event)方法即可
通过进入四个springboot自带的listners候发现,除了LoggingApplicationListener内部做了一些日志相关的动作之外,其他的什么也没做,当然我们也可以自己扩展,比如第五个就是我自己扩展的
下面贴一下第五个监听器的代码
public class MyApplicationStartedEventListener implements ApplicationListener{ @Override public void onApplicationEvent(ApplicationStartedEvent event) { SpringApplication app = event.getSpringApplication(); System.out.println("MyApplicationStartedEventListener start"); } }
当代码debug到run方法的listeners.starting时候,MyApplicationStartedEventListener start就会被打印出来。
这一篇就暂时分析到这里。