最近有時(shí)間讀了一下Spring的源碼,順便記錄一下筆記,加深理解。關(guān)于Spring IoC源碼分析,網(wǎng)上有一篇文章寫(xiě)得很詳細(xì),叫Spring IOC 容器源碼分析,大家可以去看看。這篇文章是基于XML的,因?yàn)楣ぷ髦谢谧⒔獾姆绞接玫枚嘁恍?,所以就讀了一下Spring IoC注解版本的源代碼。為了更方便的分析源碼,有時(shí)候需要對(duì)代碼一步一步進(jìn)行調(diào)試,所以我寫(xiě)了一個(gè)簡(jiǎn)單的spring-ioc-analysis,放在github上,供大家參考。
整個(gè)分析過(guò)程大概分為4篇(上,中,下和總結(jié)篇),因?yàn)闀r(shí)間和水平有限,筆記中如果有錯(cuò)誤之處,歡迎大家指正。
核心概念
在分析Spring IoC源碼之前,需要弄清楚一些核心概念。
BeanDefinition
這個(gè)是一個(gè)接口,它是用來(lái)存儲(chǔ)Bean定義的一些信息的,比如ClassName,Scope,init-methon,等等。它的實(shí)現(xiàn)有RootBeanDefination,AnnotatedGenericBeanDefinition等。
BeanDefinitionHolder
這是BeanDefination的包裝類(lèi),用來(lái)存儲(chǔ)BeanDefinition,name以及aliases等。
BeanFactory & AbstractBeanFactory
BeanFactory就是Bean工廠啦,所有的Bean都由BeanFactory統(tǒng)一創(chuàng)建和管理,Spring提供了一個(gè)AbstractBeanFactory,它繼承了BeanFactory接口,并且實(shí)現(xiàn)了大部分BeanFactory的功能。
AbstractBeanFactory有一個(gè)非常重要的方法叫g(shù)etBean()
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return doGetBean(name, requiredType, null, false);
}
它是用來(lái)根據(jù)名字和類(lèi)型獲取Bean對(duì)象的。它獲取對(duì)象的原理是,如果BeanFactory中存在Bean,則從緩存中取Bean,否則創(chuàng)建并返回該Bean,并且將該Bean添加到緩存中(這里指Singleton類(lèi)型的Bean)。所以確切的講,Bean是在什么時(shí)候創(chuàng)建的,要看什么時(shí)候調(diào)用getBean方法獲取這個(gè)Bean,根據(jù)Bean定義的不同,getBean方法會(huì)在不同時(shí)候被調(diào)用。Spring中Bean大致可以分為兩類(lèi),應(yīng)用類(lèi)Bean(被應(yīng)用程序使用)以及功能性Bean(被Spring使用)。Spring提供了一些功能性接口如BeanFactoryPostProcessor和BeanPostProcessor,實(shí)現(xiàn)了這些接口的Bean可以成為功能性Bean。如果Bean實(shí)現(xiàn)了BeanFactoryPostProcessor,則在refresh方法中調(diào)用invokeBeanFactoryPostProcessors方法時(shí)創(chuàng)建Bean,如果實(shí)現(xiàn)了BeanPostProcessor方法,則在registerBeanPostProcessors方法中創(chuàng)建Bean。其它的Bean應(yīng)該屬于應(yīng)用類(lèi)Bean,在默認(rèn)的finishBeanFactoryInitialization方法中創(chuàng)建Bean,這在后邊還會(huì)講到。
AnnotationConfigApplicationContext & BeanFactory & BeanDefinitionRegistry & DefaultListableBeanFactory
這幾個(gè)類(lèi)的關(guān)系也是很重要的,我們來(lái)捋一捋。
AnnotationConfigApplicationContext這個(gè)類(lèi)是基于注解的容器類(lèi),它實(shí)現(xiàn)了BeanFactory和BeanDefinitionRegistry兩個(gè)接口,擁有Bean對(duì)象的管理和BeanDefinition注冊(cè)功能。同時(shí)這個(gè)類(lèi)擁有一個(gè)DefaultListableBeanFactory的對(duì)象。
DefaultListableBeanFactory也實(shí)現(xiàn)了BeanFactory和BeanDefinitionRegistry接口,擁有Bean對(duì)象管理和BeanDefinition注冊(cè)功能。AnnotationConfigApplicationContext是委托DefaultListableBeanFactory來(lái)實(shí)現(xiàn)對(duì)象管理和BeanDefinition注冊(cè)的。這里使用的是代理模式。
介紹完了核心概念,我們來(lái)開(kāi)始分析源碼,剖析Spring 容器的加載過(guò)程。Spring容器啟動(dòng)過(guò)程主要做了兩件事情:
- 加載BeanDefinition
- 創(chuàng)建Bean
我們先來(lái)看BeanDefinition的加載過(guò)程。
加載BeanDefinition
我們創(chuàng)建一個(gè)簡(jiǎn)單Maven工程,在main函數(shù)中輸入如下代碼,就啟動(dòng)了一個(gè)基于注解的Spring容器,并從容器中獲取helloService對(duì)象。
public static void main(String[] args) {
AbstractApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
context.registerShutdownHook();
HelloService helloService = context.getBean(HelloService.class);
helloService.sayHello();
}
之所以要使用AbstractApplicationContext類(lèi),是因?yàn)槲覀兊腍elloService實(shí)現(xiàn)了一些BeanPostProcessor這樣的接口,需要調(diào)用AnnotationConfigApplicationContext對(duì)象的registerShutdownHook方法。
現(xiàn)在來(lái)分析源碼,進(jìn)入AnnotationConfigApplicationContext的構(gòu)造函數(shù):
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
register(annotatedClasses);
refresh();
}
兩個(gè)主方法,resister和refresh。
register
進(jìn)入register方法,它調(diào)用了reader.register方法。
public void register(Class<?>... annotatedClasses) {
Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
this.reader.register(annotatedClasses);
}
這個(gè)reader是AnnotatedBeanDefinitionReader類(lèi)的一個(gè)實(shí)例,在AnnotationConfigApplicationContext的構(gòu)造函數(shù)中創(chuàng)建的。構(gòu)造函數(shù)還創(chuàng)建了一個(gè)scanner,用于包掃描。
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
進(jìn)入reader的register方法:
public void register(Class<?>... annotatedClasses) {
for (Class<?> annotatedClass : annotatedClasses) {
registerBean(annotatedClass);
}
}
public void registerBean(Class<?> annotatedClass) {
doRegisterBean(annotatedClass, null, null, null);
}
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
// 創(chuàng)建BeanDefinition
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
// 生成bean name
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
// ...省去了其它代碼
// 創(chuàng)建BeanDefinitionHolder,它是BeanDefiniton的一個(gè)包裝類(lèi),包含BeanDefiniton對(duì)象和它的名字
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
// 最后調(diào)用registerBeanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
限于篇幅,我們只分析一些比較重要的源代碼,其它的源代碼都被我刪除了。進(jìn)入BeanDefinitionReaderUtils.registerBeanDefinition
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
// 調(diào)用registry的registerBeanDefinition方法,registry是我們傳進(jìn)來(lái)的AnnotationConfigApplicationContext,因?yàn)樗鼘?shí)現(xiàn)了BeanDefinitionRegistry,所以我們進(jìn)入AnnotationConfigApplicationContext的registerBeanDefinition方法。
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
進(jìn)入AnnotationConfigApplicationContext的registerBeanDefinition方法。好奇怪,怎么沒(méi)有呢,原來(lái)在它的父類(lèi)GenericApplicationContext中。來(lái)看代碼:
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
// 調(diào)用beanFactory的registerBeanDefinition。我們之前講過(guò),AnnotationConfigApplicationContext是委托DefaultListableBeanFactory來(lái)注冊(cè)BeanDefinition和管理Bean的,所以調(diào)用了beanFactory的registerBeanDefinition
this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
}
在GenericApplicationContext的構(gòu)造函數(shù)中,創(chuàng)建了這個(gè)beanFactory。
public GenericApplicationContext() {
// 前面也講過(guò),DefaultListableBeanFactory也實(shí)現(xiàn)了BeanDefinitionRegistry和BeanFactory接口的。
this.beanFactory = new DefaultListableBeanFactory();
}
既然beanFactory是DefaultListableBeanFactory的實(shí)例,所以進(jìn)入DefaultListableBeanFactory的registerBeanDefinition方法咯。
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
//... 省去重復(fù)注冊(cè)代碼邏輯以及其它一些邏輯判斷,
//最終執(zhí)行以下代碼,可以看出,最終是將beanDefinition放到beanDefinitionMap中。所有的beanDefinition都會(huì)放到這個(gè)map中,以beanName為主鍵。如果一個(gè)beanDefinition有多個(gè)別名,那個(gè)它會(huì)被注冊(cè)多次。
this.beanDefinitionMap.put(beanName, beanDefinition);
}
好啦,到這里為止,register方法就分析完成了。但是bean定義全部注冊(cè)完了嗎,還沒(méi)有。這里只是注冊(cè)完了配置文件的bean definition。至于我們自己注入的類(lèi),或者通過(guò)掃描注入的類(lèi),在refresh方法中,我們會(huì)在下一篇分析。
總結(jié)
我們今天講了Spring IoC容器源碼分析的第一部分,主要講了一些核心概念,以及BeanDefinition的加載過(guò)程。
在Spring中,所有用戶定義的Bean都會(huì)以BeanDefinition的方式注冊(cè)到BeanFactory中。BeanDefinition相當(dāng)于Bean的元數(shù)據(jù),描述了Bean定義的一些屬性。
我們講了AnnotationConfigApplicationContext,BeanFactory,BeanDefinitionRegistry, DefaultListableBeanFactory。AnnotationConfigApplicationContext實(shí)現(xiàn)了BeanFactory和BeanDefinitionRegistry接口,DefaultListableBeanFactory也實(shí)現(xiàn)了DefaultListableBeanFactory接口。而AnnotationConfigApplicationContext中BeanDefinition的注冊(cè)和Bean的管理,是委托給DefaultListableBeanFactory去完成的。
另外我們也分析了BeanDefinition的register過(guò)程,也確認(rèn)了AnnotationConfigApplicationContext注冊(cè)BeanDefinition確實(shí)是委托給DefaultListableBeanFactory來(lái)完成的。最終BeanDefinition被存儲(chǔ)在一個(gè)Map中,以beanName為key,以BeanDefinition對(duì)象為值。
我們下一篇會(huì)繼續(xù)講refresh方法。