直接切入正題把夸,搞懂 Bean 的加載 spring 源碼就差不多了硅则,萬卷不離其宗症见。
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(XXX.class);
app.getBean(YYY.class);
直接通過 AnnotationConfigApplicationContext 就到達(dá)入口单芜。這個 app 可以 get bean 所以 bean 在第一行就創(chuàng)建好了细疚。
public AnnotationConfigApplicationContext(Class... annotatedClasses) {
this();
this.register(annotatedClasses);
this.refresh();
}
refresh()
這個就是整個Spring Bean加載的核心了沐绒,它是ClassPathXmlApplicationContext的父類AbstractApplicationContext的一個方法俩莽,顧名思義,用于刷新整個Spring上下文信息乔遮,定義了整個Spring上下文加載的流程扮超。
public void refresh() throws BeansException, IllegalStateException {
// 對象鎖
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)用工廠處理器注冊bean
this.invokeBeanFactoryPostProcessors(beanFactory);
//注冊 bean 后置處理器
this.registerBeanPostProcessors(beanFactory);
//初始消息資源
this.initMessageSource();
//初始 event 多路廣播
this.initApplicationEventMulticaster();
//初始一些特殊的 bean
this.onRefresh();
//注冊監(jiān)聽器
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、方法是加鎖的蹋肮,這么做的原因是避免多線程同時刷新Spring上下文出刷。
2、盡管加鎖可以看到是針對整個方法體的坯辩,但是沒有在方法前加 synchronized 關(guān)鍵字馁龟,而使用了對象鎖 startUpShutdownMonitor,這樣做有兩個好處:
(1)refresh()方法和close()方法都使用了 startUpShutdownMonitor 對象鎖加鎖漆魔,這就保證了在調(diào)用 refresh() 方法的時候無法調(diào)用 close() 方法坷檩,反之亦然却音,避免了沖突。
(2)另外一個好處不在這個方法中體現(xiàn)矢炼,但是提一下系瓢,使用對象鎖可以減小了同步的范圍,只對不能并發(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方法的含義胰锌,因為這個方法會常称疲看到。Bean定義公共的抽象類是AbstractBeanDefinition资昧,普通的Bean在Spring加載Bean定義的時候爹谭,實例化出來的是GenericBeanDefinition,而Spring上下文包括實例化所有Bean用的AbstractBeanDefinition是RootBeanDefinition榛搔,這時候就使用getMergedLocalBeanDefinition方法做了一次轉(zhuǎn)化,將非RootBeanDefinition轉(zhuǎn)換為RootBeanDefinition以供后續(xù)操作东揣。
第1行~第10行的代碼是根據(jù)beanName拿到RootBeanDefinition践惑。由于此方法實例化的是所有非懶加載的單例Bean,因此要實例化Bean嘶卧,必須滿足11行的三個定義:
(1)不是抽象的
(2)必須是單例的
(3)必須是非懶加載的
接著簡單看一下第12行~第29行的代碼尔觉,這段代碼主要做的是一件事情:首先判斷一下Bean是否FactoryBean的實現(xiàn),接著判斷Bean是否SmartFactoryBean的實現(xiàn)芥吟,假如Bean是SmartFactoryBean的實現(xiàn)并且eagerInit(這個單詞字面意思是渴望加載侦铜,找不到一個好的詞語去翻譯,意思就是定義了這個Bean需要立即加載的意思)的話钟鸵,會立即實例化這個Bean钉稍。Java開發(fā)人員不需要關(guān)注這段代碼,因為SmartFactoryBean基本不會用到棺耍,我翻譯一下Spring官網(wǎng)對于SmartFactoryBean的定義描述:
-FactoryBean接口的擴(kuò)展接口贡未。接口實現(xiàn)并不表示是否總是返回單獨的實例對象,比如FactoryBean.isSingleton()實現(xiàn)返回false的情況并不清晰地表示每次返回的都是單獨的實例對象蒙袍。
-不實現(xiàn)這個擴(kuò)展接口的簡單FactoryBean的實現(xiàn)俊卤,F(xiàn)actoryBean.isSingleton()實現(xiàn)返回false總是簡單地告訴我們每次返回的都是單獨的實例對象,暴露出來的對象只能夠通過命令訪問害幅。
-注意:這個接口是一個有特殊用途的接口消恍,主要用于框架內(nèi)部使用與Spring相關(guān)。通常以现,應(yīng)用提供的FactoryBean接口實現(xiàn)應(yīng)當(dāng)只需要實現(xiàn)簡單的FactoryBean接口即可狠怨,新方法應(yīng)當(dāng)加入到擴(kuò)展接口中去
獲取Bean對象實例约啊,都是通過getBean方法,跟進(jìn)去看 doGetBean 方法取董。真正干事兒的基本上都是 do 開頭的方法棍苹。
protected <T> T doGetBean(String name, Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException {
'//提取對應(yīng)的 beanName'
final String beanName = this.transformedBeanName(name);
'// 檢查緩存中或者實例工廠中是否有對應(yīng)的實例
// 這里是為了解決單例 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 + "'");
}
}
'// 返回對應(yīng)的實例茵汰,有時候存在諸如 BeanFactory 的情況并不是直接返回實例本身而是返回指定方法返回的實例(這里應(yīng)該是用了代理)'
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
} else {
'// 只有單例情況下才會解決循環(huán)依賴'
if (this.isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
BeanFactory parentBeanFactory = this.getParentBeanFactory();
' // 如果 beanDefinitionMap 中也就是在所有已經(jīng)加載的類中不包括 beanName 則嘗試從 parentBeanFactory 中檢測'
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 {
'// 將存儲 XML 配置文件的 GernericBeanDefiniton 轉(zhuǎn)換為 RootBeanDefinitionm, 如果指定 BeanName 是子 Bean 的同時會合并父類的相關(guān)屬性'
final RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
this.checkMergedBeanDefinition(mbd, beanName, args);
String[] dependsOn = mbd.getDependsOn();
String[] var11;
'// 若存在依賴則需要遞歸實例化依賴的 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);
}
}
}
'// 實例化依賴的 bean 后便可以實例化 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 上實例化 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 的實際類型'
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;
}
}
加載過程中所涉及的步驟如下:
1.轉(zhuǎn)換對應(yīng) beanName
這里傳入的參數(shù)可能是別名枢里,也可能是 FactoryBean,所以需要進(jìn)行一系列的解析蹂午。
-去除 FactoryBean 的修飾符栏豺,如果 name 是 “&aa”,那么去除 & 使 name 為 “aa”。
-去指定的 alias 所表示的最終 beanName豆胸,例如別名 A 指向名稱為 B 的 bean 則返回 B奥洼。
2.嘗試從緩存中加載單例
單例在 Spring 的同一容器內(nèi)只會被創(chuàng)建一次,后續(xù)再獲取 bean晚胡,就直接從單例緩存中獲取了灵奖。這里只是嘗試加載,首先嘗試從緩存中加載估盘,如果加載不成功則再次嘗試從 singletonFactories 中加載瓷患。為了避免循環(huán)依賴,Spring 的原則是不等 bean 創(chuàng)建完成就會將創(chuàng)建 bean 的 ObjectFactory 提早曝光加入到緩存中遣妥。
- bean 的實例化
如果從緩存中得到了 bean 的原始狀態(tài)擅编,則需要對 bean 進(jìn)行實例化。緩存中只是最原始的 bean 狀態(tài)箫踩,并不一定是想要的爱态。假如我們要對工廠 bean 進(jìn)行處理,這里其實是工廠 bean 的初始狀態(tài)境钟,但是我們真正需要的是工廠 bean 中定義的 factory-method 方法中返回的 bean锦担,而 getObjectForBeanInstance 就是完成這個工作的。
4.原型模式的依賴檢查
只有單例情況下才會嘗試解決循環(huán)依賴吱韭,原型模式下只會拋出異常
5.檢測 parentBeanFactory
parentBeanFactory != null && !this.containsBeanDefinition(beanName) 加載的 XML 配置文件中不包含 beanName 所對應(yīng)的配置 就只能到 parentBeanFactory 去嘗試下了吆豹,然后再去遞歸的調(diào)用 getBean 方法。
6.將存儲 XML 配置文件的 GernericBeanDefinition 轉(zhuǎn)換為 RootBeanDefinition
7.尋找依賴
bean 初始化過程中很可能用到某些屬性理盆,而某些屬性可能是動態(tài)配置的痘煤,并且配置成依賴于其他的 bean, 那么這個時候就有必要先加載依賴的 bean,所以猿规,在 spring 加載循序中衷快,在初始化 bean 的時候會首先初始化這個 bean 所對應(yīng)的依賴。
8.針對不用的 scope 進(jìn)行 bean 的創(chuàng)建姨俩。
singleton prototype request 等蘸拔。
9.類型轉(zhuǎn)換
將返回的 bean 轉(zhuǎn)換為 requiredType 所指定的類型师郑。