劍指Spring原始碼(三)俯瞰Spring的Bean的生命週期(大眾版)

CodeBear發表於2019-05-15

距離上一次寫Spring原始碼解析,已經過去了快要好幾個月了,主要原因還是Spring的原始碼解析類文章太難寫了,不像我先前寫的什麼CAS原始碼,AQS原始碼,LinkedBlockingQueue等等,這些無非就是分析幾個核心方法,程式碼也不算太長,就像比較複雜的AQS原始碼也是兩篇搞定的,雖然AQS原始碼也很多東西也不能算是百分百的理解,但是核心思想應該是還算理解的。解析完畢成就感也滿滿的,寫完部落格,看著大段大段的文字,心裡也很開心:哈哈哈,原來JDK原始碼也是可以讀懂的,而且還能寫出來。但是Spring原始碼就不一樣了,如果和先前的原始碼分析類文章一樣逐行去解析的話,那麼可能一篇部落格寫下來,一個小小小小小方法都沒法分析完,就算分析完畢了,也突出不了重點啊,但是Spring原始碼解析還是要繼續的,就當做是自己的學習筆記把。

今天我們要看的內容是Spring Bean的生命週期,當然本篇部落格只是帶著大家俯瞰下,不會進行過多的原始碼分析,甚至只是貼下程式碼,不做分析,只是找到Spring Bean生命週期的回撥或者鉤子,當然這可能只是我的個人理解,大家還是要以懷疑的目光看待,也許我分析的是有問題的。

不知道Spring官方對Bean的生命問題是否有明確的定義或者解析,但是Spring In Action以及市面上流傳的大部分部落格是這樣的:

  1. 例項化Bean物件,這個時候Bean的物件是非常低階的,基本不能夠被我們使用,因為連最基本的屬性都沒有設定,可以理解為連Autowired註解都是沒有解析的;
  2. 填充屬性,當做完這一步,Bean物件基本是完整的了,可以理解為Autowired註解已經解析完畢,依賴注入完成了;
  3. 如果Bean實現了BeanNameAware介面,則呼叫setBeanName方法;
  4. 如果Bean實現了BeanClassLoaderAware介面,則呼叫setBeanClassLoader方法;
  5. 如果Bean實現了BeanFactoryAware介面,則呼叫setBeanFactory方法;
  6. 呼叫BeanPostProcessor的postProcessBeforeInitialization方法;
  7. 如果Bean實現了InitializingBean介面,呼叫afterPropertiesSet方法;
  8. 如果Bean定義了init-method方法,則呼叫Bean的init-method方法;
  9. 呼叫BeanPostProcessor的postProcessAfterInitialization方法;當進行到這一步,Bean已經被準備就緒了,一直停留在應用的上下文中,直到被銷燬;
  10. 如果應用的上下文被銷燬了,如果Bean實現了DisposableBean介面,則呼叫destroy方法,如果Bean定義了destory-method宣告瞭銷燬方法也會被呼叫。

為了驗證上面的邏輯,可以做個試驗:

首先定義了一個Bean,裡面有各種回撥和鉤子,其中需要注意下,我在SpringBean的構造方法中列印了studentService,看SpringBean被new的出來的時候,studentService是否被注入了;又在setBeanName中列印了studentService,看此時studentService是否被注入了,以此來驗證,Bean是何時完成的自動注入的(這個StudentServiceImpl 類的程式碼就不貼出來了,無非就是一個最普通的Bean):

public class SpringBean implements InitializingBean, DisposableBean, BeanNameAware, BeanFactoryAware, BeanClassLoaderAware {

    public SpringBean() {
        System.out.println("SpringBean構造方法:" + studentService);
        System.out.println("SpringBean構造方法");
    }

    @Autowired
    StudentServiceImpl studentService;

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("destroy");
    }

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        System.out.println("setBeanClassLoader");
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("setBeanFactory");
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("setBeanName:" + studentService);
        System.out.println("setBeanName");
    }

    public void initMethod() {
        System.out.println("initMethod");
    }

    public void destroyMethod() {
        System.out.println("destroyMethod");
    }
}

再定義一個BeanPostProcessor,在重寫的兩個方法中進行了判斷,如果傳進來的beanName是springBean才進行列印:

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if(beanName.equals("springBean")) {
            System.out.println("postProcessBeforeInitialization");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if(beanName.equals("springBean")) {
            System.out.println("postProcessAfterInitialization");
        }
        return bean;
    }
}

定義一個配置類,完成自動掃描,但是SpringBean是手動註冊的,並且宣告瞭initMethod和destroyMethod:

@Configuration
@ComponentScan
public class AppConfig {
    @Bean(initMethod = "initMethod",destroyMethod = "destroyMethod")
    public SpringBean springBean() {
        return new SpringBean();
    }
}

最後就是啟動類了:

    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext =
                new AnnotationConfigApplicationContext(AppConfig.class);
        annotationConfigApplicationContext.destroy();
    }

執行結果:

SpringBean構造方法:null
SpringBean構造方法
setBeanName:com.codebear.StudentServiceImpl@31190526
setBeanName
setBeanClassLoader
setBeanFactory
postProcessBeforeInitialization
afterPropertiesSet
initMethod
postProcessAfterInitialization
destroy
destroyMethod

可以看到,試驗結果和上面分析的完全一致。

這就是廣為流傳的Spring生命週期。

也許你在應付面試的時候,是死記硬背這些結論的,現在我帶著你找到這些方法,跟我來。

首先我們來到AnnotationConfigApplicationContext的構造方法:

    //根據引數型別可以知道,其實可以傳入多個annotatedClasses,但是這種情況出現的比較少
    public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
        //呼叫無參建構函式,會先呼叫父類GenericApplicationContext的建構函式
        //父類的建構函式裡面就是初始化DefaultListableBeanFactory,並且賦值給beanFactory
        //本類的建構函式裡面,初始化了一個讀取器:AnnotatedBeanDefinitionReader read,一個掃描器ClassPathBeanDefinitionScanner scanner
        //scanner的用處不是很大,它僅僅是在我們外部手動呼叫 .scan 等方法才有用,常規方式是不會用到scanner物件的
        this();
        //把傳入的類進行註冊,這裡有兩個情況,
        //傳入傳統的配置類
        //傳入bean(雖然一般沒有人會這麼做
        //看到後面會知道spring把傳統的帶上@Configuration的配置類稱之為FULL配置類,不帶@Configuration的稱之為Lite配置類
        //但是我們這裡先把帶上@Configuration的配置類稱之為傳統配置類,不帶的稱之為普通bean
        register(annotatedClasses);
        //重新整理
        refresh();
    }

進入refresh方法,refresh方法中有一個finishBeanFactoryInitialization小方法,這個方法是用來例項化懶載入單例Bean的,也就是我們的Bean都是在這裡被建立出來的(當然我這裡說的的是絕大部分情況是這樣的):

finishBeanFactoryInitialization(beanFactory);

我們再進入finishBeanFactoryInitialization這方法,裡面有一個beanFactory.preInstantiateSingletons()方法:

        //初始化所有的非懶載入單例
        beanFactory.preInstantiateSingletons();

我們嘗試再點進去,這個時候你會發現這是一個介面,好在它只有一個實現類,所以可以我們來到了他的唯一實現,實現類就是org.springframework.beans.factory.support.DefaultListableBeanFactory,這裡面是一個迴圈,我們的Bean就是迴圈被建立出來的,我們找到其中的getBean方法:

getBean(beanName);

這裡有一個分支,如果Bean是FactoryBean,如何如何,如果Bean不是FactoryBean如何如何,好在不管是不是FactoryBean,最終還是會呼叫getBean方法,所以我們可以毫不猶豫的點進去,點進去之後,你會發現,這是一個門面方法,直接呼叫了doGetBean方法:

    return doGetBean(name, null, null, false);

再進去,不斷的深入,接近我們要尋找的東西。
這裡面的比較複雜,但是有我在,我可以直接告訴你,下一步我們要進入哪裡,我們要進入

if (mbd.isSingleton()) {

                    //getSingleton中的第二個引數型別是ObjectFactory<?>,是一個函式式介面,不會立刻執行,而是在
                    //getSingleton方法中,呼叫ObjectFactory的getObject,才會執行createBean
                    sharedInstance = getSingleton(beanName, () -> {
                        try {
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            destroySingleton(beanName);
                            throw ex;
                        }
                    });
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }

這裡面的createBean方法,再點進去啊,但是又點不進去了,這是介面啊,但是別慌,這個介面又只有一個實現類,所以說 沒事,就是幹,這個實現類為org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory。

這個實現的方法裡面又做了很多事情,我們就不去看了,我就是帶著大家找到那幾個生命週期的回撥到底定義在哪裡就OK了。

    Object beanInstance = doCreateBean(beanName, mbdToUse, args);//建立bean,核心
            if (logger.isDebugEnabled()) {
                logger.debug("Finished creating instance of bean '" + beanName + "'");
            }
            return beanInstance;

再繼續深入doCreateBean方法,這個方法又做了一堆一堆的事情,但是值得開心的事情就是 我們已經找到了我們要尋找的東西了。

建立例項

首先是建立例項,位於:

instanceWrapper = createBeanInstance(beanName, mbd, args);//建立bean的例項。核心

填充屬性

其次是填充屬性,位於:

populateBean(beanName, mbd, instanceWrapper);//填充屬性,炒雞重要

在填充屬性下面有一行程式碼:

    exposedObject = initializeBean(beanName, exposedObject, mbd);

繼續深入進去。

aware系列介面的回撥

aware系列介面的回撥位於initializeBean中的invokeAwareMethods方法:

invokeAwareMethods(beanName, bean);
private void invokeAwareMethods(final String beanName, final Object bean) {
        if (bean instanceof Aware) {
            if (bean instanceof BeanNameAware) {
                ((BeanNameAware) bean).setBeanName(beanName);
            }
            if (bean instanceof BeanClassLoaderAware) {
                ClassLoader bcl = getBeanClassLoader();
                if (bcl != null) {
                    ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
                }
            }
            if (bean instanceof BeanFactoryAware) {
                ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
            }
        }
    }

BeanPostProcessor的postProcessBeforeInitialization方法

BeanPostProcessor的postProcessBeforeInitialization方法位於initializeBean的

if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }
    @Override
    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
            throws BeansException {

        Object result = existingBean;
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            Object current = processor.postProcessBeforeInitialization(result, beanName);
            if (current == null) {
                return result;
            }
            result = current;
        }
        return result;
    }

afterPropertiesSet init-method

afterPropertiesSet init-method位於initializeBean中的

    invokeInitMethods(beanName, wrappedBean, mbd);

這裡面呼叫了兩個方法,一個是afterPropertiesSet方法,一個是init-method方法:

    ((InitializingBean) bean).afterPropertiesSet();
invokeCustomInitMethod(beanName, bean, mbd);

BeanPostProcessor的postProcessAfterInitialization方法

BeanPostProcessor的postProcessAfterInitialization方法位於initializeBean的

if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }
    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
            throws BeansException {

        Object result = existingBean;
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            Object current = processor.postProcessAfterInitialization(result, beanName);
            if (current == null) {
                return result;
            }
            result = current;
        }
        return result;
    }

當然在實際的開發中,應該沒人會去銷燬Spring的應用上下文把,所以剩餘的兩個銷燬的回撥就不去找了。

這就是廣為流傳的Spring Bean的生命週期,我也帶著大家找到了各種回撥和鉤子,但是我認為這並非是Spring Bean完整的生命週期,只是經過簡化的,那麼我認為的完整的生命週期是如何的呢,請聽下回分解。

相關文章