spring源碼:bean的加載
測試代碼
//xml配置文件的解析
ClassPathResource resource = new ClassPathResource("spring.xml");
BeanFactory beanFactory = new XmlBeanFactory(resource);
//bean的加載,這篇文章就是講解這一句代碼
MyTestBean myTestBean = (MyTestBean) beanFactory.getBean("myTestBean");
System.out.println(myTestBean.getTestStr());
跟蹤入口
通過跟蹤AbstractBeanFactory類的getBean(String name);
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
找到實際加載函數是doGetBean()方法
去掉干擾代碼,只看主要代碼
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
//1.轉換對應的beanName
final String beanName = transformedBeanName(name);
Object bean;
//2. 直接從三級緩存(單例對象、單例提前曝光的對象、單例對象工廠)中獲取bean實例
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
//3.返回bean,有時候並不是直接返回實例本身,而是返回指定方法返回的實例
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// 4. 原型模式的依賴檢查,例如A還未創建完成的時候 因爲B的創建 再次創建A,就會造成循環依賴
//當isPrototypeCurrentlyInCreation=true時,也就是說當前bean正在創建中,也就時說明存在循環依賴
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
//5.如果beanDefinitionMap中也就是所有已經加載的類中不包括beanName則嘗試從parentBeanFactory中查找
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// // 如果沒有,查詢父工廠
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// // 執行帶有args參數的getbean方法
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// 如果沒有參數,執行標準的getbean方法
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
//如果不僅僅是做類型檢查,那麼需要標記此Bean正在創建之中
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
// 6.將存儲xml的GernericBeanDefinition轉換爲RootBeanDefinition
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
//如果beanName對應的類是子類的話,則會合並父類的相關屬性
checkMergedBeanDefinition(mbd, beanName, args);
// 7. 獲取依賴的Bean
String[] dependsOn = mbd.getDependsOn();
//若存在依賴則遞歸實例化依賴的bean
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
//8.針對不同的scope進行bean的創建
// 創建單例bean
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
//把當前的beanName加入正在創建beanName的集合中,會在第一步判斷
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
//把當前的beanName從正在創建beanName的集合中移除
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
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, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, 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;
}
}
// 9.檢查類型,如果不滿足可以進行類型轉換,如果轉換器進行不了這兩種類型的轉換,則拋出異常
//將bean轉換成requiredType所指定的類型
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
從上面源碼中可以看到,bean的加載主要是這九步。下面就會一步一步的講解這九步。我們可以先不要深究這個方法中的代碼,先從整體瞭解一下這個方法的主題結構。
1. 轉換對應的beanName
實現方法: transformedBeanName(name)
返回值:真實的beanName
方法說明:doGetBean方法傳入的name,可能並不是beanName,也可能是別名或者是FactoryBean,如果是別名alias,則需要找到對應的beanName;如果是FactoryBean,則需要去除name中&符。
2. 從緩存中加載單例
實現方法: getSingleton(beanName);
返回值:beanName對應的單例對象sharedInstance
方法說明:單例在spring同一容器中只會被創建一次,後續直接就從單例緩存中獲取。
下面是該方法源碼:
DefaultSingletonBeanRegistry.java
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//1.從單例緩存中獲取實例
Object singletonObject = this.singletonObjects.get(beanName);
//isSingletonCurrentlyInCreation判斷此單例是否正在創建
//檢查這個bean是不是null,並且這個bean正在創建中的bean的map緩存(singletonsCurrentlyInCreation)中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
//走到這裏證明,bean不在單例緩存中,而且有程序在創建beanName
//則鎖住單例緩存
synchronized (this.singletonObjects) {
// 2.從提前暴光的單例對象緩存中獲取 bean
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 都沒有
// 3.從單例工廠的緩存中找到對應的單例工廠生產提前暴光的單例
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//生產單例bean
singletonObject = singletonFactory.getObject();
//添加提前暴光的單例的緩存中
this.earlySingletonObjects.put(beanName, singletonObject);
//移除對應bean工廠
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
代碼 中的註釋已經很詳細了,不在贅述。
值得一說的是,爲什麼要這麼多層緩存?其實是爲了檢測是否涉及循環依賴。
singletonObjects:用於保存BeanName和創建的bean實例,是個Map對象。
singletonFactories:用戶保存beanName和創建bean的工廠,是個Map對象。
earlySingletonObjects:用戶保存beanName和創建的bean實例,與singletonObjects不同的是,這裏面放的bean還在創建中,可以通過getBean()方法獲取到bean,目的是用來檢測循環依賴。
3. bean的實例化
實現方法:getObjectForBeanInstance(sharedInstance, name, beanName, null);
返回值:真正想要返回的bean
方法說明:從緩存中或者createBean()獲取的都是bean的原始狀態,此方法就是對bean進行實例化。需要強調的是,最原始的bean並不一定是我們真正想要的bean。例如,像要factory-method方法返回的bean.
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// 若name傳遞的是如“&student”(以&爲前綴)
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
//該bean不是FactoryBean,拋出異常
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
}
// 如果beanInstance不是FactoryBean,是一個普通的Bean,直接返回
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
if (mbd == null) {
//根據beanName從緩存中加載bean,注意此處的beanName是包含‘&’符
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
//到這裏已經明確知道beanInstance是FactoryBean類型了
// 從工廠中返回bean實例
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// 判斷已加載的類中是否定義beanname
if (mbd == null && containsBeanDefinition(beanName)) {
//如果對應的bean是子bean的話,則合併父類的相關屬性
mbd = getMergedLocalBeanDefinition(beanName);
}
//是否是用戶生成的:判斷是用戶生成還是應用程序生成
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
- getCachedObjectForFactoryBean(beanName); 獲取bean
FactoryBeanRegistrySupport.java
/** FactoryBean 創建的單例對象的緩存: FactoryBean name --> object */
private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(16);
protected Object getCachedObjectForFactoryBean(String beanName) {
return this.factoryBeanObjectCache.get(beanName);
}
- getObjectFromFactoryBean(factory, beanName, !synthetic);真正獲取FactoryBean的bean
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
// 從緩存中獲取,factoryBeanObjectCache存放<FactoryBean名稱,Object>
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
// 緩存中獲取不到,從factory中獲取
object = doGetObjectFromFactoryBean(factory, beanName);
// 有可能當執行doGetObjectFromFactoryBean函數時,Bean正在創建,所以此時再獲取一下
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (shouldPostProcess) {
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
return object;
}
beforeSingletonCreation(beanName);
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
afterSingletonCreation(beanName);
}
}
if (containsSingleton(beanName)) {
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
else {
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
從上門代碼可以知道主要創建bean實例的代碼在doGetObjectFromFactoryBean(factory, beanName);方法中,我們繼續追蹤到此方法:
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException {
Object object;
try {
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
//getObject()方法在實現FactoryBean接口時實現的
object = factory.getObject();
}
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null) {
if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
object = new NullBean();
}
return object;
}
上面這麼多的代碼其實真正邏輯沒有幾行,在doGetObjectFromFactoryBean方法中我們終於看到了factory.getObject();創建FactoryBean實例的代碼。這一邏輯到此也結束了。
4 . 原型模式的依賴檢查
說明:只有在單例情況下才會嘗試解決循環依賴。
5. 檢測parentBeanFactory()父工廠
7. 尋找依賴
說明:因爲bean的初始化過程中很可能用到某些屬性,而這些屬性很可能是動態配置的。所以要先加載依賴的bean.
8.根據不同的scope進行bean的創建
scope的類型:基本作用域(singleton、prototype),Web 作用域(reqeust、session、globalsession),自定義作用域。
說明:從doGetBean()方法中知道對不同的scope,創建bean的邏輯都封裝在createBean()方法中,下面就去看一看這個方法。
這裏太長了,會專門也一篇文章spring源碼:bean的創建
9. 類型轉換
把bean轉換成參數requiredType類型的。