Spring5原始碼解析9-doGetBean概述
接上回,AbstractApplicationContext#refresh
呼叫AbstractApplicationContext#finishBeanFactoryInitialization
來初始化所有的非懶載入單例 Bean。在該AbstractApplicationContext#finishBeanFactoryInitialization
方法內部通過呼叫AbstractBeanFactory#doGetBean
來獲取 Spring 容器所管理的 Bean。
AbstractBeanFactory#doGetBean
AbstractBeanFactory#doGetBean
原始碼如下:
protected <T> T doGetBean(final String name,@Nullable final Class<T> requiredType,@Nullable final Object[] args,boolean typeCheckOnly) throws BeansException {
// 如果這個 name 是 FactoryBean 的beanName (&+beanName),就刪除&,返回beanName,傳入的name也可以是別名,也需要做轉換
// 注意 beanName 和 name 變數的區別,beanName是經過處理的,經過處理的beanName就直接對應singletonObjects中的key
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
// 根據beanName嘗試從singletonObjects獲取Bean
// 獲取不到則再嘗試從earlySingletonObjects,singletonFactories 從獲取Bean
// 這段程式碼和解決迴圈依賴有關
Object sharedInstance = getSingleton(beanName);
// 第一次進入sharedInstance肯定為null
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
} else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// 如果sharedInstance不為null,也就是非第一次進入
// 為什麼要呼叫 getObjectForBeanInstance 方法,判斷當前Bean是不是FactoryBean,如果是,那麼要不要呼叫getObject方法
// 因為傳入的name變數如果是(&+beanName),那麼beanName變數就是(beanName),也就是說,程式在這裡要返回FactoryBean
// 如果傳入的name變數(beanName),那麼beanName變數也是(beanName),但是,之前獲取的sharedInstance可能是FactoryBean,需要通過sharedInstance來獲取對應的Bean
// 如果傳入的name變數(beanName),獲取的sharedInstance就是對應的Bean的話,就直接返回Bean
bean = getObjectForBeanInstance(sharedInstance,name,beanName,null);
} else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
// 判斷是否迴圈依賴
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
// 獲取父BeanFactory,一般情況下,父BeanFactory為null,如果存在父BeanFactory,就先去父級容器去查詢
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup,requiredType,args,typeCheckOnly);
} else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup,args);
} else if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup,requiredType);
} else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
// 建立的Bean是否需要進行型別驗證,一般情況下都不需要
if (!typeCheckOnly) {
// 標記 bean 已經被建立
markBeanAsCreated(beanName);
}
try {
// 獲取其父類Bean定義,子類合併父類公共屬性
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd,args);
// Guarantee initialization of beans that the current bean depends on.
// 獲取當前Bean依賴的Bean的名稱,@DependsOn
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName,dep)) {
throw new BeanCreationException(mbd.getResourceDescription(),"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
// 如果當前Bean依賴其他Bean,把被依賴Bean註冊給當前Bean
registerDependentBean(dep,beanName);
try {
// 先去建立所依賴的Bean
getBean(dep);
} catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(),"'" + beanName + "' depends on missing bean '" + dep + "'",ex);
}
}
}
// Create bean instance.
if (mbd.isSingleton()) {
// 建立單例Bean
sharedInstance = getSingleton(beanName,() -> {
try {
return createBean(beanName,mbd,args);
} catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process,to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance,mbd);
} else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
// 建立prototype Bean,每次都會建立一個新的物件
Object prototypeInstance = null;
try {
// 回撥beforePrototypeCreation方法,註冊當前建立的原型物件
beforePrototypeCreation(beanName);
// 建立物件
prototypeInstance = createBean(beanName,args);
} finally {
// 回撥 afterPrototypeCreation 方法,告訴容器該Bean的原型物件不再建立
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance,mbd);
} else {
// 如果既不是單例Bean,也不是prototype,則獲取其Scope
String scopeName = mbd.getScope();
final 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,() -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName,args);
} finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance,mbd);
} catch (IllegalStateException ex) {
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",ex);
}
}
} catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// Check if required type matches the type of the actual bean instance.
// 對建立的Bean進行型別檢查
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean,requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name,bean.getClass());
}
return convertedBean;
} catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'",ex);
}
throw new BeanNotOfRequiredTypeException(name,bean.getClass());
}
}
return (T) bean;
}
複製程式碼
主要流程都已經在上述的原始碼中增加了註釋,讀者可以自己查閱。其中,我覺得最主要是要明白以下幾點:
Object sharedInstance = getSingleton(beanName);
Object sharedInstance = getSingleton(beanName);
這段程式碼是解決迴圈依賴的關鍵,先大概看一下,留個印象,具體的等後面有空講一下迴圈依賴吧。
public Object getSingleton(String beanName) {
return getSingleton(beanName,true);
}
//getSingleton(beanName,true);原始碼
@Nullable
protected Object getSingleton(String beanName,boolean allowEarlyReference) {
//singletonObjects 就是Spring內部用來存放單例Bean的物件池,key為beanName,value為Bean
Object singletonObject = this.singletonObjects.get(beanName);
// singletonsCurrentlyInCreation 存放了當前正在建立的bean的BeanName
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// earlySingletonObjects 是早期單例Bean的快取池,此時Bean已經被建立(newInstance),但是還沒有完成初始化
// key為beanName,value為Bean
singletonObject = this.earlySingletonObjects.get(beanName);
//是否允許早期依賴
if (singletonObject == null && allowEarlyReference) {
//singletonFactories 單例工廠的快取,key為beanName,value 為ObjectFactory
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//獲取早期Bean
singletonObject = singletonFactory.getObject();
//將早期Bean放到earlySingletonObjects中
this.earlySingletonObjects.put(beanName,singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
複製程式碼
transformedBeanName 和 getObjectForBeanInstance 的作用
呼叫doGetBean
方法時會傳入name
變數,表明需要從容器中獲取那個 Bean。transformedBeanName
除了在處理別名之外,這裡會有以下幾種情況:
第一種情況,直接往容器中註冊 Bean。
@Bean
public UserBean userBean() {
return new UserBean("shen",111);
}
複製程式碼
在這種情況下,name
變數如果為userBean
,那麼就是要從容器中獲取UserBean
物件。
呼叫transformedBeanName
方法返回beanName
物件的取值userBean
。
然後根據beanName
去容器中獲取相應的Bean
,而獲取到的就是UserBean
物件。
最後呼叫getObjectForBeanInstance
方法,返回的還是UserBean
物件。
第二種情況,通過FactoryBean
往容器中註冊 Bean
@Bean
public FactoryBean userBean() {
return new FactoryBean<UserBean>() {
@Override
public UserBean getObject() throws Exception {
return new UserBean("shen",111);
}
@Override
public Class<?> getObjectType() {
return UserBean.class;
}
};
}
複製程式碼
這裡又可以分為兩種情況:
第一種情況:
如果name
變數如果為userBean
,那麼也要從容器中獲取UserBean
物件。
呼叫transformedBeanName
方法返回beanName
物件的取值為userBean
。
然後根據beanName
去容器中獲取相應的Bean
,而獲取到的是FactoryBean
物件。
最後呼叫getObjectForBeanInstance
方法,發現是從容器中獲取UserBean
物件,於是呼叫FactoryBean#getObject
返回UserBean
物件。
第二種情況:
name
變數如果為&userBean
,那麼就是要從容器中獲取FactoryBean
物件本身。
呼叫transformedBeanName
方法返回beanName
物件的取值為userBean
。
然後根據beanName
去容器中獲取相應的Bean
,而獲取到的是FactoryBean
物件,
最後呼叫getObjectForBeanInstance
方法,就是要獲取FactoryBean
物件,於是方法返回FactoryBean
物件。
@DependsOn
通過原始碼可以知道,Spring 在建立 Bean 之前,首先會建立當前 Bean 所有依賴的 Bean。
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName,dep)) {
throw new BeanCreationException(mbd.getResourceDescription(),"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
// 如果當前Bean依賴其他Bean,把被依賴Bean註冊給當前Bean
registerDependentBean(dep,beanName);
try {
// 先去建立所依賴的Bean
getBean(dep);
} catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(),ex);
}
}
}
複製程式碼
那什麼是當前 Bean 所有依賴的 Bean 呢?也就是說,String[] dependsOn = mbd.getDependsOn();
什麼情況下這個陣列中會有值呢?
在 Spring 中有這個一個註解:@DependsOn
。這個註解一般用的很少(碰巧最近專案中用到了這個註解,哈哈哈)。來看一下 Spring 檔案中是怎麼描述的:
Beans on which the current bean depends. Any beans specified are guaranteed to be created by the container before this bean. Used infrequently in cases where a bean does not explicitly depend on another through properties or constructor arguments,but rather depends on the side effects of another bean's initialization. A depends-on declaration can specify both an initialization-time dependency and,in the case of singleton beans only,a corresponding destruction-time dependency. Dependent beans that define a depends-on relationship with a given bean are destroyed first,prior to the given bean itself being destroyed. Thus,a depends-on declaration can also control shutdown order.
機器翻譯:當前 bean 所依賴的 bean。任何指定的 bean 都保證在此 bean 之前由容器建立。當一個 bean 不是通過屬性或建構函式引數顯式依賴於另一個 bean,而是依賴於另一個 bean 初始化的副作用時,很少使用。依賴項宣告既可以指定初始化時間依賴項,也可以指定(在只有單例 bean 的情況下)對應的銷燬時間依賴項。在銷燬給定 bean 之前,首先銷燬定義與給定 bean 的依賴關係的依賴 bean。因此,依賴宣告也可以控制關機順序。
舉個例子
@Service
public class OrderService {
public OrderService() {
System.out.println("OrderService create");
}
@PreDestroy
public void destroy() {
System.out.println("OrderService destroy");
}
}
複製程式碼
@DependsOn("orderService")
@Service
public class UserService {
public UserService() {
System.out.println("UserService create");
}
@PreDestroy
public void destroy() {
System.out.println("UserService destroy");
}
}
複製程式碼
@Configuration
@ComponentScan
public class DependsOnMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(DependsOnMain.class);
context.close();
}
}
複製程式碼
//執行結果
OrderService create
UserService create
UserService destroy
OrderService destroy
複製程式碼
createBean(beanName,args);
在 Spring 中存在者多種 scope,Spring 會根據不用的 scope 選用不同的初始化方式。但是,不管怎麼樣,Spring 在底層建立 Bean 的時候都是通過呼叫AbstractAutowireCapableBeanFactory#createBean
方法來建立物件的。
那 Spring 究竟是怎麼建立 Bean 的呢?AbstractAutowireCapableBeanFactory#createBean
方法內部到底做了什麼事情呢?迴圈依賴該怎麼解決呢?
未完待續...
原始碼註釋 GITHUB 地址:github.com/shenjianeng…