直接切入正題,搞懂 Bean 的加載 spring 源碼就差不多了,萬(wàn)卷不離其宗。
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(XXX.class);
app.getBean(YYY.class);
直接通過(guò) AnnotationConfigApplicationContext 就到達(dá)入口。這個(gè) app 可以 get bean 所以 bean 在第一行就創(chuàng)建好了。
public AnnotationConfigApplicationContext(Class... annotatedClasses) {
this();
this.register(annotatedClasses);
this.refresh();
}
refresh()
這個(gè)就是整個(gè)Spring Bean加載的核心了,它是ClassPathXmlApplicationContext的父類AbstractApplicationContext的一個(gè)方法,顧名思義,用于刷新整個(gè)Spring上下文信息,定義了整個(gè)Spring上下文加載的流程。
public void refresh() throws BeansException, IllegalStateException {
// 對(duì)象鎖
synchronized(this.startupShutdownMonitor) {
//準(zhǔn)備刷新上下文 (設(shè)置激活標(biāo)志位)
this.prepareRefresh();
//獲取刷新Spring上下文的Bean工廠
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
//準(zhǔn)備 bean 工廠
this.prepareBeanFactory(beanFactory);
try {
//允許 beanFactory 的 后置處理器
this.postProcessBeanFactory(beanFactory);
//調(diào)用工廠處理器注冊(cè)bean
this.invokeBeanFactoryPostProcessors(beanFactory);
//注冊(cè) bean 后置處理器
this.registerBeanPostProcessors(beanFactory);
//初始消息資源
this.initMessageSource();
//初始 event 多路廣播
this.initApplicationEventMulticaster();
//初始一些特殊的 bean
this.onRefresh();
//注冊(cè)監(jiān)聽(tīng)器
this.registerListeners();
// 這里完成bean 的初始化(非懶加載)
this.finishBeanFactoryInitialization(beanFactory);
// 發(fā)布相關(guān)事件
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
//刪除 bean
this.destroyBeans();
//取消 refresh
this.cancelRefresh(var9);
throw var9;
} finally {
// reset 激活標(biāo)志位
this.resetCommonCaches();
}
}
}
1、方法是加鎖的,這么做的原因是避免多線程同時(shí)刷新Spring上下文。
2、盡管加鎖可以看到是針對(duì)整個(gè)方法體的,但是沒(méi)有在方法前加 synchronized 關(guān)鍵字,而使用了對(duì)象鎖 startUpShutdownMonitor,這樣做有兩個(gè)好處:
(1)refresh()方法和close()方法都使用了 startUpShutdownMonitor 對(duì)象鎖加鎖,這就保證了在調(diào)用 refresh() 方法的時(shí)候無(wú)法調(diào)用 close() 方法,反之亦然,避免了沖突。
(2)另外一個(gè)好處不在這個(gè)方法中體現(xiàn),但是提一下,使用對(duì)象鎖可以減小了同步的范圍,只對(duì)不能并發(fā)的代碼塊進(jìn)行加鎖,提高了整體代碼運(yùn)行的效率。
finishBeanFactoryInitialization(beanFactory) 主要完成 bean 的加載。
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
if (beanFactory.containsBean("conversionService") && beanFactory.isTypeMatch("conversionService", ConversionService.class)) {
beanFactory.setConversionService((ConversionService)beanFactory.getBean("conversionService", ConversionService.class));
}
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(new StringValueResolver() {
public String resolveStringValue(String strVal) {
return AbstractApplicationContext.this.getEnvironment().resolvePlaceholders(strVal);
}
});
}
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
String[] var3 = weaverAwareNames;
int var4 = weaverAwareNames.length;
for(int var5 = 0; var5 < var4; ++var5) {
String weaverAwareName = var3[var5];
this.getBean(weaverAwareName);
}
beanFactory.setTempClassLoader((ClassLoader)null);
beanFactory.freezeConfiguration();
beanFactory.preInstantiateSingletons();
}
preInstantiateSingletons 方法是初始化單例 bean 的方法:
public void preInstantiateSingletons() throws BeansException {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Pre-instantiating singletons in " + this);
}
List<String> beanNames = new ArrayList(this.beanDefinitionNames);
Iterator var2 = beanNames.iterator();
while(true) {
while(true) {
String beanName;
RootBeanDefinition bd;
do {
do {
do {
if (!var2.hasNext()) {
var2 = beanNames.iterator();
while(var2.hasNext()) {
beanName = (String)var2.next();
Object singletonInstance = this.getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton)singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
smartSingleton.afterSingletonsInstantiated();
return null;
}
}, this.getAccessControlContext());
} else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
return;
}
beanName = (String)var2.next();
bd = this.getMergedLocalBeanDefinition(beanName);
} while(bd.isAbstract());
} while(!bd.isSingleton());
} while(bd.isLazyInit());
if (this.isFactoryBean(beanName)) {
final FactoryBean<?> factory = (FactoryBean)this.getBean("&" + beanName);
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = (Boolean)AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
public Boolean run() {
return ((SmartFactoryBean)factory).isEagerInit();
}
}, this.getAccessControlContext());
} else {
isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean)factory).isEagerInit();
}
if (isEagerInit) {
this.getBean(beanName);
}
} else {
this.getBean(beanName);
}
}
}
}
這里先解釋一下getMergedLocalBeanDefinition方法的含義,因?yàn)檫@個(gè)方法會(huì)常常看到。Bean定義公共的抽象類是AbstractBeanDefinition,普通的Bean在Spring加載Bean定義的時(shí)候,實(shí)例化出來(lái)的是GenericBeanDefinition,而Spring上下文包括實(shí)例化所有Bean用的AbstractBeanDefinition是RootBeanDefinition,這時(shí)候就使用getMergedLocalBeanDefinition方法做了一次轉(zhuǎn)化,將非RootBeanDefinition轉(zhuǎn)換為RootBeanDefinition以供后續(xù)操作。
第1行~第10行的代碼是根據(jù)beanName拿到RootBeanDefinition。由于此方法實(shí)例化的是所有非懶加載的單例Bean,因此要實(shí)例化Bean,必須滿足11行的三個(gè)定義:
(1)不是抽象的
(2)必須是單例的
(3)必須是非懶加載的
接著簡(jiǎn)單看一下第12行~第29行的代碼,這段代碼主要做的是一件事情:首先判斷一下Bean是否FactoryBean的實(shí)現(xiàn),接著判斷Bean是否SmartFactoryBean的實(shí)現(xiàn),假如Bean是SmartFactoryBean的實(shí)現(xiàn)并且eagerInit(這個(gè)單詞字面意思是渴望加載,找不到一個(gè)好的詞語(yǔ)去翻譯,意思就是定義了這個(gè)Bean需要立即加載的意思)的話,會(huì)立即實(shí)例化這個(gè)Bean。Java開(kāi)發(fā)人員不需要關(guān)注這段代碼,因?yàn)镾martFactoryBean基本不會(huì)用到,我翻譯一下Spring官網(wǎng)對(duì)于SmartFactoryBean的定義描述:
-FactoryBean接口的擴(kuò)展接口。接口實(shí)現(xiàn)并不表示是否總是返回單獨(dú)的實(shí)例對(duì)象,比如FactoryBean.isSingleton()實(shí)現(xiàn)返回false的情況并不清晰地表示每次返回的都是單獨(dú)的實(shí)例對(duì)象。
-不實(shí)現(xiàn)這個(gè)擴(kuò)展接口的簡(jiǎn)單FactoryBean的實(shí)現(xiàn),F(xiàn)actoryBean.isSingleton()實(shí)現(xiàn)返回false總是簡(jiǎn)單地告訴我們每次返回的都是單獨(dú)的實(shí)例對(duì)象,暴露出來(lái)的對(duì)象只能夠通過(guò)命令訪問(wèn)。
-注意:這個(gè)接口是一個(gè)有特殊用途的接口,主要用于框架內(nèi)部使用與Spring相關(guān)。通常,應(yīng)用提供的FactoryBean接口實(shí)現(xiàn)應(yīng)當(dāng)只需要實(shí)現(xiàn)簡(jiǎn)單的FactoryBean接口即可,新方法應(yīng)當(dāng)加入到擴(kuò)展接口中去
獲取Bean對(duì)象實(shí)例,都是通過(guò)getBean方法,跟進(jìn)去看 doGetBean 方法。真正干事兒的基本上都是 do 開(kāi)頭的方法。
protected <T> T doGetBean(String name, Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException {
'//提取對(duì)應(yīng)的 beanName'
final String beanName = this.transformedBeanName(name);
'// 檢查緩存中或者實(shí)例工廠中是否有對(duì)應(yīng)的實(shí)例
// 這里是為了解決單例 bean 下的循環(huán)依賴
//spring 創(chuàng)建 bean 的原則是不等 bean 創(chuàng)建完就將 創(chuàng)建 bean 的 ObjectFactory 提早曝光。
//也就是將 ObjectFactory 加入到緩存中'
Object sharedInstance = this.getSingleton(beanName);
Object bean;
if (sharedInstance != null && args == null) {
if (this.logger.isDebugEnabled()) {
if (this.isSingletonCurrentlyInCreation(beanName)) {
this.logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");
} else {
this.logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
'// 返回對(duì)應(yīng)的實(shí)例,有時(shí)候存在諸如 BeanFactory 的情況并不是直接返回實(shí)例本身而是返回指定方法返回的實(shí)例(這里應(yīng)該是用了代理)'
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
} else {
'// 只有單例情況下才會(huì)解決循環(huán)依賴'
if (this.isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
BeanFactory parentBeanFactory = this.getParentBeanFactory();
' // 如果 beanDefinitionMap 中也就是在所有已經(jīng)加載的類中不包括 beanName 則嘗試從 parentBeanFactory 中檢測(cè)'
if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {
String nameToLookup = this.originalBeanName(name);
'// 遞歸到 BeanFactory 中尋找'
if (args != null) {
return parentBeanFactory.getBean(nameToLookup, args);
}
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
'// 如果不是僅僅做類型檢查則是創(chuàng)建 bean 這里要記錄'
if (!typeCheckOnly) {
this.markBeanAsCreated(beanName);
}
try {
'// 將存儲(chǔ) XML 配置文件的 GernericBeanDefiniton 轉(zhuǎn)換為 RootBeanDefinitionm, 如果指定 BeanName 是子 Bean 的同時(shí)會(huì)合并父類的相關(guān)屬性'
final RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
this.checkMergedBeanDefinition(mbd, beanName, args);
String[] dependsOn = mbd.getDependsOn();
String[] var11;
'// 若存在依賴則需要遞歸實(shí)例化依賴的 bean'
if (dependsOn != null) {
var11 = dependsOn;
int var12 = dependsOn.length;
for(int var13 = 0; var13 < var12; ++var13) {
String dep = var11[var13];
if (this.isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
'// 緩存依賴調(diào)用'
this.registerDependentBean(dep, beanName);
try {
this.getBean(dep);
} catch (NoSuchBeanDefinitionException var24) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", var24);
}
}
}
'// 實(shí)例化依賴的 bean 后便可以實(shí)例化 mbd本身了'
if (mbd.isSingleton()) {
sharedInstance = this.getSingleton(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
try {
return AbstractBeanFactory.this.createBean(beanName, mbd, args);
} catch (BeansException var2) {
AbstractBeanFactory.this.destroySingleton(beanName);
throw var2;
}
}
});
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
'// 原型模式的創(chuàng)建'
} else if (mbd.isPrototype()) {
var11 = null;
Object prototypeInstance;
try {
this.beforePrototypeCreation(beanName);
prototypeInstance = this.createBean(beanName, mbd, args);
} finally {
this.afterPrototypeCreation(beanName);
}
bean = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
} else {
'// 指定的 scope 上實(shí)例化 bean'
String scopeName = mbd.getScope();
Scope scope = (Scope)this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
AbstractBeanFactory.this.beforePrototypeCreation(beanName);
Object var1;
try {
var1 = AbstractBeanFactory.this.createBean(beanName, mbd, args);
} finally {
AbstractBeanFactory.this.afterPrototypeCreation(beanName);
}
return var1;
}
});
bean = this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
} catch (IllegalStateException var23) {
throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton", var23);
}
}
} catch (BeansException var26) {
this.cleanupAfterBeanCreationFailure(beanName);
throw var26;
}
}
'// 檢查需要的類型是否符合 bean 的實(shí)際類型'
if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
try {
return this.getTypeConverter().convertIfNecessary(bean, requiredType);
} catch (TypeMismatchException var25) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", var25);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
} else {
return bean;
}
}
加載過(guò)程中所涉及的步驟如下:
1.轉(zhuǎn)換對(duì)應(yīng) beanName
這里傳入的參數(shù)可能是別名,也可能是 FactoryBean,所以需要進(jìn)行一系列的解析。
-去除 FactoryBean 的修飾符,如果 name 是 “&aa”,那么去除 & 使 name 為 “aa”。
-去指定的 alias 所表示的最終 beanName,例如別名 A 指向名稱為 B 的 bean 則返回 B。
2.嘗試從緩存中加載單例
單例在 Spring 的同一容器內(nèi)只會(huì)被創(chuàng)建一次,后續(xù)再獲取 bean,就直接從單例緩存中獲取了。這里只是嘗試加載,首先嘗試從緩存中加載,如果加載不成功則再次嘗試從 singletonFactories 中加載。為了避免循環(huán)依賴,Spring 的原則是不等 bean 創(chuàng)建完成就會(huì)將創(chuàng)建 bean 的 ObjectFactory 提早曝光加入到緩存中。
- bean 的實(shí)例化
如果從緩存中得到了 bean 的原始狀態(tài),則需要對(duì) bean 進(jìn)行實(shí)例化。緩存中只是最原始的 bean 狀態(tài),并不一定是想要的。假如我們要對(duì)工廠 bean 進(jìn)行處理,這里其實(shí)是工廠 bean 的初始狀態(tài),但是我們真正需要的是工廠 bean 中定義的 factory-method 方法中返回的 bean,而 getObjectForBeanInstance 就是完成這個(gè)工作的。
4.原型模式的依賴檢查
只有單例情況下才會(huì)嘗試解決循環(huán)依賴,原型模式下只會(huì)拋出異常
5.檢測(cè) parentBeanFactory
parentBeanFactory != null && !this.containsBeanDefinition(beanName) 加載的 XML 配置文件中不包含 beanName 所對(duì)應(yīng)的配置 就只能到 parentBeanFactory 去嘗試下了,然后再去遞歸的調(diào)用 getBean 方法。
6.將存儲(chǔ) XML 配置文件的 GernericBeanDefinition 轉(zhuǎn)換為 RootBeanDefinition
7.尋找依賴
bean 初始化過(guò)程中很可能用到某些屬性,而某些屬性可能是動(dòng)態(tài)配置的,并且配置成依賴于其他的 bean, 那么這個(gè)時(shí)候就有必要先加載依賴的 bean,所以,在 spring 加載循序中,在初始化 bean 的時(shí)候會(huì)首先初始化這個(gè) bean 所對(duì)應(yīng)的依賴。
8.針對(duì)不用的 scope 進(jìn)行 bean 的創(chuàng)建。
singleton prototype request 等。
9.類型轉(zhuǎn)換
將返回的 bean 轉(zhuǎn)換為 requiredType 所指定的類型。