Spring源碼之九finishRefresh詳解
Spring源碼之九finishRefresh詳解
公眾號搜索【程式設計師田同學】,專職程式設計師兼業餘寫手,生活不止於寫程式碼
Spring IoC 的核心內容要收尾了,本文將對最後一個方法 finishRefresh 進行介紹,位於refresh 方法中的第九個位置。
本章實際是對發布訂閱模式的一種補充,這是Spring在刷新事件完成後發布事件。
由於存在上下文關係,本文也會對 initApplicationEventMulticaster 方法、registerListeners 方法進行回顧。
我們回到refresh 方法中。
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//1、刷新前的準備
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
//2、將會初始化 BeanFactory、載入 Bean、註冊 Bean
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
//3、設置 BeanFactory 的類載入器,添加幾個 BeanPostProcessor,手動註冊幾個特殊的 bean
prepareBeanFactory(beanFactory);
try {
//4、模板方法
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
//執行BeanFactory後置處理器
invokeBeanFactoryPostProcessors(beanFactory);
// 5、Register bean processors that intercept bean creation.
//註冊bean後置處理器
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
//國際化
initMessageSource();
// Initialize event multicaster for this context.
//初始化事件廣播器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
//6、模板方法--springboot實現了這個方法
onRefresh();
// Check for listener beans and register them.
//7、註冊監聽器
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//8、完成bean工廠的初始化**方法重要**********************************************
finishBeanFactoryInitialization(beanFactory);
//9、 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();
}
}
}
我們首先知道這個三個方法的作用:
initApplicationEventMulticaster():初始化應用的事件廣播器
/**
* Initialize the ApplicationEventMulticaster.
* Uses SimpleApplicationEventMulticaster if none defined in the context.
* @see org.springframework.context.event.SimpleApplicationEventMulticaster
*/
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 1.判斷BeanFactory是否已經存在事件廣播器(固定使用beanName=applicationEventMulticaster)
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
// 1.1 如果已經存在,則將該bean賦值給applicationEventMulticaster
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
// 1.2 如果不存在,則使用SimpleApplicationEventMulticaster
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
最終只做了一件事,初始化應用的事件廣播器。(具體什麼是事件廣播器及其作用可見上上篇文章,具體就不在吃贅述了)
registerListeners():註冊監聽器。見上上篇文章
finishRefresh():完成上下文的刷新工作,本文重點。
首先概覽finishRefresh方法
protected void finishRefresh() {
// Clear context-level resource caches (such as ASM metadata from scanning).
//清除資源快取
clearResourceCaches();
// Initialize lifecycle processor for this context.
// // 1.為此上下文初始化生命周期處理器
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
// 2.首先將刷新完畢事件傳播到生命周期處理器(觸發isAutoStartup方法返回true的SmartLifecycle的start方法)
getLifecycleProcessor().onRefresh();
// Publish the final event.
// 3.推送上下文刷新完畢事件到相應的監聽器
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}
1、2、3是重點內容
1.為此上下文初始化生命周期處理器
protected void initLifecycleProcessor() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 1.判斷BeanFactory是否已經存在生命周期處理器(固定使用beanName=lifecycleProcessor)
if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {
this.lifecycleProcessor =
beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);
if (logger.isTraceEnabled()) {
logger.trace("Using LifecycleProcessor [" + this.lifecycleProcessor + "]");
}
}
else {
// 1.2 如果不存在,則使用DefaultLifecycleProcessor
DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();
defaultProcessor.setBeanFactory(beanFactory);
this.lifecycleProcessor = defaultProcessor;
// 並將DefaultLifecycleProcessor作為默認的生命周期處理器,註冊到BeanFactory中
beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);
if (logger.isTraceEnabled()) {
logger.trace("No '" + LIFECYCLE_PROCESSOR_BEAN_NAME + "' bean, using " +
"[" + this.lifecycleProcessor.getClass().getSimpleName() + "]");
}
}
}
2.首先將刷新完畢事件傳播到生命周期處理器
private void startBeans(boolean autoStartupOnly) {
// 1.獲取所有的Lifecycle bean
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
// 將Lifecycle bean 按階段分組,階段通過實現Phased介面得到
Map<Integer, LifecycleGroup> phases = new HashMap<>();
// 2.遍歷所有Lifecycle bean,按階段值分組
lifecycleBeans.forEach((beanName, bean) -> {
// autoStartupOnly=true代表是ApplicationContext刷新時容器自動啟動;autoStartupOnly=false代表是通過顯示的調用啟動
// 3.當autoStartupOnly=false,也就是通過顯示的調用啟動,會觸發全部的Lifecycle;
// 當autoStartupOnly=true,也就是ApplicationContext刷新時容器自動啟動,只會觸發isAutoStartup方法返回true的SmartLifecycle
if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
// 3.1 獲取bean的階段值(如果沒有實現Phased介面,則值為0)
int phase = getPhase(bean);
// 3.2 拿到存放該階段值的LifecycleGroup
LifecycleGroup group = phases.get(phase);
if (group == null) {
// 3.3 如果該階段值的LifecycleGroup為null,則新建一個
group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
phases.put(phase, group);
}
// 3.4 將bean添加到該LifecycleGroup
group.add(beanName, bean);
}
});
// 4.如果phases不為空
if (!phases.isEmpty()) {
List<Integer> keys = new ArrayList<>(phases.keySet());
// 4.1 按階段值進行排序
Collections.sort(keys);
// 4.2 按階段值順序,調用LifecycleGroup中的所有Lifecycle的start方法
for (Integer key : keys) {
phases.get(key).start();
}
}
}
3.推送上下文刷新完畢事件到相應的監聽器
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
// Decorate event as an ApplicationEvent if necessary
// 1.如有必要,將事件裝飾為ApplicationEvent
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
else {
applicationEvent = new PayloadApplicationEvent<>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
}
}
// Multicast right now if possible - or lazily once the multicaster is initialized
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
// 2.使用事件廣播器廣播事件到相應的監聽器
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// Publish event via parent context as well...
// 3.同樣的,通過parent發布事件.....
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
這裡面調用的publishEvent方法,和我們自定義的監聽器調用的publishEvent是同一個方法,ContextRefreshedEvent是Spirng的一個事件稱為上下文刷新完畢事件,如果我們在上下文刷新完成後要寫一個發布事件,實現ApplicationListener
我們在此舉一個簡單的例子。
這樣,當 Spring 執行到 finishRefresh 方法時,就會將 ContextRefreshedEvent 事件推送到 MyRefreshedListener 中。
讀者可以結合自定義事件對比一個和Spring提供的刷新上下文事件的區別,以便於更好的理解Spring的事件監聽機制。
跟 ContextRefreshedEvent 相似的還有:ContextStartedEvent、ContextClosedEvent、ContextStoppedEvent。
好啦,Spirng的refresh方法到這裡就結束啦,一共是九篇部落格,實際上這也是Spirng的IOC的全部內容了,如果讀者能把九篇的完全消化,那麼spring的IOC也就理解的七七八八了。