寫在最前
當(dāng)我們運(yùn)行Web容器或是以SE的方式運(yùn)行Spring程序的過程中岭洲,你有沒有想過Spring是如何實(shí)現(xiàn)回調(diào)生命周期中的那些過程呢?今天我們就以生命周期中回調(diào)Aware接口為例,來說說Spring的回調(diào)過程顾翼。
正文
1.Aware接口
Aware接口在Spring的3.1版本中出現(xiàn)芋忿,并且beans包中,屬于spring的核心蒋荚。上圖中的描述告訴我們戳稽,Aware是一個具有標(biāo)識作用的超級接口,實(shí)現(xiàn)該接口的bean是具有被spring 容器通知的能力的期升,而被通知的方式就是通過回調(diào)广鳍。對于這段英文,我并沒有直譯吓妆,而是加上了自己的理解赊时。總之行拢,一句話也就是說:直接或間接實(shí)現(xiàn)了這個接口的類祖秒,都具有被spring容器通知的能力。
那我們看看spring中實(shí)現(xiàn)了該超級接口的子接口有哪些舟奠?
哇竭缝,多如牛毛!咦沼瘫,別動抬纸,有幾個好熟悉的接口。例如:ResourceLoaderAware耿戚、BeanNameAware湿故、ApplicationContextAware阿趁、BeanNameAware... 熟悉spring生命周期的童鞋可能見過這些接口。不錯坛猪,這些接口就是今天我們的主角脖阵。
2.Spring Boot的大致啟動過程
我們以Spring Boot的啟動過程為例,看看這些Aware接口是如何被調(diào)用到的墅茉。
如上圖命黔,這里是以內(nèi)嵌jetty的方式啟動Spring Boot。 通常我們啟動Spring boot就斤,都是直接調(diào)用SpringApplication的run方法悍募,再看看run方法的內(nèi)部:
主要看紅色圈起的地方,其它的代碼可以忽略洋机。這里調(diào)用了createApplicationContext方法去創(chuàng)建容器上下文坠宴。再來看看createApplicationContext()方法的內(nèi)部:
webEnvironment是一個boolean型的變量,用來表示當(dāng)前的應(yīng)用類型是不是web應(yīng)用槐秧。如果為false啄踊,則代表是普通應(yīng)用(JavaSE);反之就是web應(yīng)用(Java Web)刁标,則創(chuàng)建可運(yùn)行web應(yīng)用的上下文颠通。我們講述的是web應(yīng)用,所以這里的contextClass是AnnotationConfigEmbeddedWebApplicationContext膀懈。createApplicationContext()方法中的最后一行代碼是創(chuàng)建了一個context顿锰。我們跟進(jìn)去看看這個context是如何創(chuàng)建的:
上圖中的第七行代碼,通過反射實(shí)例化了contextClass启搂,這里實(shí)例化的正是AnnotationConfigEmbeddedWebApplicationContext類硼控,調(diào)用的是無參的構(gòu)造器。我們再去看看AnnotationConfigEmbeddedWebApplicationContext的無參構(gòu)造器:
如上圖胳赌,構(gòu)造器中只是設(shè)置了reader和scanner牢撼。這里我們先忽略它們。除此之外疑苫,實(shí)例化一個類時它的直接或間接的父類也同樣會被實(shí)例化熏版。看看AnnotationConfigEmbeddedWebApplicationContext有些哪些父類:
我們耐心的一層一層的跟蹤父類和間接父類的構(gòu)造器到GenericApplicationContext才發(fā)現(xiàn)無參構(gòu)造器中在做一些事情捍掺。如下圖:
看到這里撼短,我們終于看見曙光了。xxxBeanFactory是生成beans對象的工廠類挺勿。在DefaultListableBeanFactory的父類AbstractAutowireCapableBeanFactory中有兩個很重要的方法:
initializeBean()和createBean()方法曲横。initializeBean是用來初始化beans的,看下圖代碼:
看到這里我們就知道了不瓶,Aware系列的接口是這么被調(diào)用的了禾嫉,并把需要的內(nèi)部對象回傳給Aware的子類實(shí)例對象灾杰,那么外部就可以獲取到spring內(nèi)部的一些對象了。例如:我們獲取BeanFactory夭织,然后手動創(chuàng)建beans對象等等吭露。
寫在最后
看完上面的過程有沒有發(fā)現(xiàn)少了點(diǎn)什么東西吠撮? 是不是發(fā)現(xiàn)少了:Spring Boot是如何調(diào)用到initializeBean()的呢尊惰?欲知后事如何,且看下回分解泥兰。