Spring容器啟動流程+Bean的生命週期【附原始碼】

天喬巴夏丶發表於2020-09-09

如果對SpringIoc與Aop的原始碼感興趣,可以訪問參考:https://javadoop.com/,十分詳細。

Spring容器的啟動全流程

Spring容器的啟動流程如下,這是我在看原始碼過程中自己總結的流程圖,如有錯誤,還望評論區指點:

接下來附上原始碼:

為什麼是refresh方法命名,而不是init命名呢?

其實,在ApplicaitonContext建立起來之後,可以通過refresh進行重建,將原來的ac銷燬,重新執行一次初始化操作,用refresh更加貼切。

public ClassPathXmlApplicationContext(
    String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
    throws BeansException {
    //如果已經有application Context ,並需要配置成父子關係, 呼叫該構造方法
    super(parent);
    // 根據提供的路徑,處理成配置檔案陣列(以分號、逗號、空格、tab、換行符分割)
    setConfigLocations(configLocations);
    if (refresh) {
        refresh();//核心!!!
    }

}

雖然ApplicationContext繼承自BeanFactory,更確切地說是ApplicationContext內部持有了一個例項化的BeanFactory(DefaultListableBeanFactory)BeanFactory的相關操作其實是委託給這個例項來處理。

@Override
public void refresh() throws BeansException, IllegalStateException {
    //保證容器啟動銷燬操作的併發安全
    synchronized (this.startupShutdownMonitor) {
        //準備工作, 記錄容器的啟動時間, 標記已啟動狀態, 處理配置檔案種的佔位符
        prepareRefresh();

        //這步用於將配置檔案解析成一個個bean definition,註冊到重建的beanFactory中,(只是提取了配置資訊,bean並沒有初始化),同時還設定兩個配置屬性:1、是否允許bean覆蓋2、是否允許迴圈引用
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        //設定beanFactory的類載入器, 新增幾個beanPostProcessor ,手動註冊幾個特殊的bean
        prepareBeanFactory(beanFactory);
        try {
            //如果bean實現了beanFactoryPostProcessor 將會執行postProcessBeanFactory方法  提供子類的擴充套件點,到這bean都載入、註冊完成,但沒有初始化,具體的子類可以在這步新增特殊bfpp實現類做事
            postProcessBeanFactory(beanFactory);

            //呼叫bfpp的各個實現類的ppbf方法
            invokeBeanFactoryPostProcessors(beanFactory);

            //註冊BeanPostProcessor的實現類,BeanPostProcessor將在bean初始化前後執行
            registerBeanPostProcessors(beanFactory);

            //初始化當前 ApplicationContext 的 MessageSource,國際化
            initMessageSource();

            //初始化當前 ApplicationContext 的事件廣播器
            initApplicationEventMulticaster();

            //模板方法(鉤子方法,具體的子類可以在這裡初始化一些特殊的 Bean(在初始化 singleton beans 之前)
            onRefresh();

            //註冊事件監聽器,監聽器需要實現 ApplicationListener 介面。
            registerListeners();

            //例項化+初始化所有的非懶載入的單例bean
            finishBeanFactoryInitialization(beanFactory);

            //廣播事件,ApplicationContext 初始化完成
            finishRefresh();
        }

        catch (BeansException ex) {
            // Destroy already created singletons to avoid dangling resources.銷燬已經初始化的 singleton 的 Beans,以免有些 bean 會一直佔用資源
            destroyBeans();
            cancelRefresh(ex);
            // Propagate exception to caller.
            throw ex;
        }
        finally {
            resetCommonCaches();
        }
    }
}

利用註解方式大致也是按照這個流程一步步下來,不同在於,AnnotationConfigApplicationContext在執行構造器的時候,已經通過scan(basePackages);將beanDefination讀取到。

將bean的定義轉化為BeanDefination:

如果利用AnnotationConfigApplicationContext。

	public AnnotationConfigApplicationContext(String... basePackages) {
		this();
		scan(basePackages);//這個過程中配置已經被轉化為一個個的beanDefinition
		refresh();
	}

Spring容器關閉流程

protected void doClose() {
    if (this.active.get() && this.closed.compareAndSet(false, true)) {
        if (logger.isDebugEnabled()) {
            logger.debug("Closing " + this);
        }
		//取消註冊上下文
        if (!IN_NATIVE_IMAGE) {
            LiveBeansView.unregisterApplicationContext(this);
        }
        // 釋出事件
        publishEvent(new ContextClosedEvent(this));

        // 停止所有Lifecycle bean,以避免在銷燬期間造成延遲。
        if (this.lifecycleProcessor != null) {
            this.lifecycleProcessor.onClose();
        }

        // 銷燬上下文的BeanFactory中所有快取的單例。
        destroyBeans();

        // 關閉此上下文字身的狀態。
        closeBeanFactory();

        // 讓子類善後
        onClose();

        // 充值本地應用堅硬其為pre-refresh狀態
        if (this.earlyApplicationListeners != null) {
            this.applicationListeners.clear();
            this.applicationListeners.addAll(this.earlyApplicationListeners);
        }

        // 切換為非活動狀態
        this.active.set(false);
    }
}

大概就是:先發布事件,再摧毀Factory中的bean,再摧毀Factory本身,最後設定一些狀態。

而Bean週期中的銷燬部分就存在於destroyBeans中。當然,銷燬bean也是需要先銷燬它所依賴的bean。

Bean 的生命週期


在瞭解Bean的生命週期之前,我們必須要明確SpringBean和我們通常說的物件有什麼區別?

SpringBean是由SpringIoC容器管理的,是一個被例項化,組裝,並通過容器管理的物件,可通過getBean()獲取。容器通過讀取配置的後設資料,解析成BeanDefinition,註冊到BeanFactory中,加入到singletonObjects快取池中

Bean的建立

在上面的流程中,只有到finishBeanFactoryInitialization(beanFactory);這一步,才開始對非懶載入例項的例項化+ 初始化。

//例項化所有剩餘的非懶載入的單例bean
beanFactory.preInstantiateSingletons();

可以看一下這一步的具體實現:DefaultListableBeanFactory

public void preInstantiateSingletons() throws BeansException {
    //擁有所有的beanNames
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
    // 觸發所有非懶載入的singleton beans的例項化+初始化操作
    for (String beanName : beanNames) {
        //對bean繼承的處理,合併父bean 中的配置
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        //非抽象,非懶載入的singletons
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            //處理factoryBean
            if (isFactoryBean(beanName)) {
                //如果是factoryBean,在beanName錢加上&,再呼叫getBean方法
                Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                if (bean instanceof FactoryBean) {
                    FactoryBean<?> factory = (FactoryBean<?>) bean;
                    boolean isEagerInit;
                    //判斷當前 FactoryBean 是否是 SmartFactoryBean 的實現
                    if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                        isEagerInit = AccessController.doPrivileged(
                            (PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
                            getAccessControlContext());
                    }
                    else {
                        isEagerInit = (factory instanceof SmartFactoryBean &&
                                       ((SmartFactoryBean<?>) factory).isEagerInit());
                    }
                    if (isEagerInit) {
                        getBean(beanName);
                    }
                }
            }
            else {
                getBean(beanName);//普通的bean,直接呼叫getBean進行例項化
            }
        }
    }
}

只有!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()條件滿足的時候,這一步才會進行例項化,另外,Spring還對其是否為FactoryBean進行判斷,當然了,一般來說,最最普通的bean都會在最後一個else分支中進行例項化。

doGetBean全流程

這部分篇幅過長,我直接放上總結的流程圖:

createBean

那麼createBean又幹了什麼事呢,稍微看看就可以:

//省略許多異常處理的部分
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    throws BeanCreationException {//初始化階段的args == null
    RootBeanDefinition mbdToUse = mbd;
	// 確保 BeanDefinition 中的 Class 被載入
    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }
    // 準備方法覆寫它來自於 bean 定義中的 <lookup-method /> 和 <replaced-method />
    mbdToUse.prepareMethodOverrides();
    // 讓 InstantiationAwareBeanPostProcessor 在這一步有機會返回代理
    Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
    if (bean != null) {
        return bean;
	// 重頭戲,建立 bean
    Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    return beanInstance;
}

我們的重點放在Object beanInstance = doCreateBean(beanName, mbdToUse, args);這一步上,我們已經知道,Bean的例項化+初始化都在這一步中完成。

doCreateBean

在這個doCreateBean方法中,存在三個重要方法:

createBeanInstance 建立例項

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    //確保已經載入了這個class
    Class<?> beanClass = resolveBeanClass(mbd, beanName);
    //校驗這個類的訪問許可權
    if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
        throw new BeanCreationException();
    }
	//spring5.0 返回建立bean例項的回撥
    Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
    if (instanceSupplier != null) {
        return obtainFromSupplier(instanceSupplier, beanName);
    }
    if (mbd.getFactoryMethodName() != null) {
        //採用工廠方法例項化
        return instantiateUsingFactoryMethod(beanName, mbd, args);
    }
    // 如果是第二次建立 如prototype bean,這種情況下,我們可以從第一次建立知道,採用無參建構函式,還是建構函式依賴注入 來完成例項化
    boolean resolved = false;
    boolean autowireNecessary = false;
    if (args == null) {
        synchronized (mbd.constructorArgumentLock) {
            if (mbd.resolvedConstructorOrFactoryMethod != null) {
                resolved = true;
                autowireNecessary = mbd.constructorArgumentsResolved;
            }
        }
    }
    if (resolved) {
        if (autowireNecessary) {
            //建構函式注入
            return autowireConstructor(beanName, mbd, null, null);
        }
        else {
            //無參建構函式
            return instantiateBean(beanName, mbd);
        }
    }

    // 判斷是否採用有參建構函式
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
        mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
        //args!=null 的建構函式注入(有參)
        return autowireConstructor(beanName, mbd, ctors, args);
    }

    // Preferred constructors for default construction?
    ctors = mbd.getPreferredConstructors();
    if (ctors != null) {
        //判斷是否採用首選的建構函式
        return autowireConstructor(beanName, mbd, ctors, null);
    }

    // 呼叫無參建構函式
    return instantiateBean(beanName, mbd);
}

以無參建構函式為例,例項化的過程在SimpleInstantiationStrategy中。

  • 如果不存在方法重寫:可以直接使用Java的反射進行例項化。
  • 否則使用CGLIB實現例項化。
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
    // 如果不存在方法覆寫,就是用java的反射進行例項化, 否則使用CGLIB
    if (!bd.hasMethodOverrides()) {
        Constructor<?> constructorToUse;
        synchronized (bd.constructorArgumentLock) {
            constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
            if (constructorToUse == null) {
                final Class<?> clazz = bd.getBeanClass();
                if (clazz.isInterface()) {
                    throw new BeanInstantiationException(clazz, "Specified class is an interface");
                }
                try {
                    if (System.getSecurityManager() != null) {
                        constructorToUse = AccessController.doPrivileged(
                            (PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
                    }
                    else {
                        constructorToUse = clazz.getDeclaredConstructor();
                    }
                    bd.resolvedConstructorOrFactoryMethod = constructorToUse;
                }
                catch (Throwable ex) {
                    throw new BeanInstantiationException(clazz, "No default constructor found", ex);
                }
            }
        }
        //利用構造方法進行例項化
        return BeanUtils.instantiateClass(constructorToUse);
    }
    else {
        // 存在方法覆寫的情況,需要利用CGLIB來完成例項化,需要依賴於CGLIB生成子類
        return instantiateWithMethodInjection(bd, beanName, owner);
    }
}

此時,Bean例項已經通過構造方法或者工廠方法建立,但是其中的屬性,如依賴注入的各種屬性尚未填充。

populateBean 填充屬性

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    if (bw == null) {
        if (mbd.hasPropertyValues()) {//this.propertyValues bean例項的所有屬性
            throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
        }
        else {
            // Skip property population phase for null instance.
            return;
        }
    }
    //在設定屬性之前,給所有InstantiationAwareBeanPostProcessor機會修改bean的狀態
    // 【此時bean的狀態 = 已經通過工廠方法或者構造方法例項化,在屬性賦值之前】。例如,可以使用支援欄位注入的樣式。InstantiationAwareBeanPostProcessor
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
            if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                return;
            }
        }
    }

    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);//獲取PropertyValue物件

    int resolvedAutowireMode = mbd.getResolvedAutowireMode();
    if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {//獲取Autowire的模式  or 通過名字, or 通過型別
        MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
        // 通過名字找到所有屬性值,如果是 bean 依賴,先初始化依賴的 bean。記錄依賴關係
        if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
            autowireByName(beanName, mbd, bw, newPvs);
        }
        // 通過型別裝配 記錄依賴關係
        if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
            autowireByType(beanName, mbd, bw, newPvs);
        }
        pvs = newPvs;
    }
	//...省略
    //設定bean例項的屬性值
    if (pvs != null) {
        applyPropertyValues(beanName, mbd, bw, pvs);
    }
}

initializeBean 回撥方法

屬性注入完成,處理各種回撥,如BeanNameAware、BeanClassLoaderAware、BeanFactoryAware等。

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {//
    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            invokeAwareMethods(beanName, bean);
            return null;
        }, getAccessControlContext());
    }
    else {
        invokeAwareMethods(beanName, bean);//如果bean實現了BeanNameAware、BeanClassLoaderAware、BeanFactoryAware介面, 回撥
    }

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);//BeanPostProcessor 的 postProcessBeforeInitialization 回撥
    }

    try {
        invokeInitMethods(beanName, wrappedBean, mbd);//處理bean中定義的init-method或 bean實現了InitializingBean ,呼叫afterPropertiesSet() 方法
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
    }
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);//BeanPostProcessor 的 postProcessAfterInitialization 回撥
    }

    return wrappedBean;
}

Bean的銷燬

DisposableBeanAdapter.java

@Override
public void destroy() {
    //CommonAnnotationBeanPostProcessorc 處理@preDetroy
    if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
        for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
            processor.postProcessBeforeDestruction(this.bean, this.beanName);
        }
    }

    if (this.invokeDisposableBean) {////DisposableBean的destroy方法
        ((DisposableBean) this.bean).destroy();
        }
    }

    if (this.destroyMethod != null) {//destroy-method方法
        invokeCustomDestroyMethod(this.destroyMethod);
    }
    else if (this.destroyMethodName != null) {
        Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);
        if (methodToInvoke != null) {
            invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
        }
    }
}

參考資料:

相關文章