【超詳細的Spring源碼分析 —— 06 Spring對於Bean管理的核心組件源碼分析 - 實例化 Bean Definition】

不知道各位還記不記得 Spring 對 bean 生命週期的管理方式:Spring 默認採用單例的方式管理 Bean,在獲取 Bean 實例的時候會經過一個緩存進行獲取,若是還未初始化,那麼就會先將 Bean Definition 進行一個初始化放入緩存,而後再經過緩存獲取。java

那麼在上一章中,我也在總結中提到過:在執行完 beanDefinitionReader.loadBeanDefinitions(resource); 這段代碼以後,僅僅是完成了 beanDefinition 的解析與註冊,還未到初始化階段。緩存

在這一章中,我將詳細對 bean 在什麼時候進行實例化、如何放入緩存這部分的內容進行詳細的分析。併發

1、Bean 的實例化

首先是方法入口,也就是咱們獲取 bean 實例的代碼:app

Student student = defaultListableBeanFactory.getBean("student", Student.class);
複製代碼

咱們深刻到 getBean() 這個方法中:ide

AbstractBeanFactory.getBean()post

能夠發現,這裏調用的是 AbstractBeanFactory 的 getBean() 方法,它是 DefaultListableBeanFactory 的父類。ui

這裏分別 getBean() 方法進行了不一樣的重載,而且底層是調用了 doGetBean() 這個方法:this

//---------------------------------------------------------------------
// Implementation of BeanFactory interface
//---------------------------------------------------------------------

@Override
public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
}

@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
    return doGetBean(name, requiredType, null, false);
}

@Override
public Object getBean(String name, Object... args) throws BeansException {
    return doGetBean(name, null, args, false);
}
複製代碼

繼續深刻到 doGetBean() :spa

AbstractBeanFactory.doGetBean()prototype

這個方法的代碼很是的多,咱們當下先關注從緩存獲取 bean 實例的邏輯,所以我先省略掉後續的代碼:

@SuppressWarnings("unchecked")
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
    
    // 獲取到bean的惟一標識
    final String beanName = transformedBeanName(name);
    Object bean;
    
    // 提前地去檢查緩存中是否存在相應的bean實例
    // 若是存在就返回相應的單例bean
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
    
    //....
}
複製代碼

能夠發現上面這個方法會從單例緩存池中獲取單例bean實例,因而咱們能夠接着深刻:

@Override
@Nullable
public Object getSingleton(String beanName) {
    return getSingleton(beanName, true);
}
複製代碼

深刻到重載的 getgetSingleton() 方法

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 經過單例bean緩存 singletonObjects 獲取到對應的實例
    // 這裏的容器依然是經過 ConcurrentHashMap 來實現的
    // key=惟一標識、value=單例bean實例
    Object singletonObject = this.singletonObjects.get(beanName);
    
    // 若是發現緩存中不存在對應的bean實例, 而且發現這個bean正處於建立過程當中
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        // 那麼就會進行一個同步
        // 避免併發環境下出現的讀寫不一致的問題
    	synchronized (this.singletonObjects) {
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
            	ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
            	if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
            	}
            }
    	}
    }
    return singletonObject;
}
複製代碼

咱們回到 doGetBean() ,看看後續會進行什麼邏輯:

@SuppressWarnings("unchecked")
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
    final String beanName = transformedBeanName(name);
    Object bean;

    // 若是緩存池中存在相應的實例, 在這裏就會直接進行返回
    // 沒有的話就會返回一個空值
    Object sharedInstance = getSingleton(beanName);
   
    // 若是成功從單例緩存池中獲取到了實例
    if (sharedInstance != null && args == null) {
        // 緊接着去打印一下日誌
        if (logger.isTraceEnabled()) {
            //....
        }
        // 將緩存中獲取到的Object轉換爲bean實例
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }
    // 這裏就是緩存池中不存在實例的邏輯了
    else {
        // 判斷是不是prototype這種類型的bean正在被建立
        // 若是是, 直接拋出異常
        if (isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }
    
        // 下面這塊邏輯就是檢查 BeanDefinition 是否在工廠中存在
        BeanFactory parentBeanFactory = getParentBeanFactory();
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            //....
        }
    
        if (!typeCheckOnly) {
            markBeanAsCreated(beanName);
        }
        
        try {
            // 獲取到 BeanDefinition
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            checkMergedBeanDefinition(mbd, beanName, args);
        
            // 檢查 bean 的依賴關係
            // 好比 A 依賴於 B, 那麼就須要先把 B 建立出來
            String[] dependsOn = mbd.getDependsOn();
            if (dependsOn != null) {
                //....
            }
        
            // 真正建立 bean 實例的邏輯
            if (mbd.isSingleton()) { // 判斷scope是不是singleton
                // 這裏經過了 lambda 表達式來處理方法的執行
                // 首先會建立一個bean實例, 而後 getSingleton() 方法又會將建立好的 bean 實例緩存到單例緩存池
                sharedInstance = getSingleton(beanName, () -> {
                    try {
                        // 這裏就會進行一個 bean 實例的建立流程
                        return createBean(beanName, mbd, args);
                    }
                    catch (BeansException ex) {
                        destroySingleton(beanName);
                        throw ex;
                   }
                });
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }
            // 判斷scope是不是prototype
            else if (mbd.isPrototype()) {
                // ....省略
            }
            else { // 這邊就是其餘scope類型的bean實例化的邏輯
                // ....省略
            }
        catch (BeansException ex) {
            cleanupAfterBeanCreationFailure(beanName);
            throw ex;
        }
    }
    
    // ...省略
    return (T) bean;
}
複製代碼

經過上述代碼,咱們可以明確,這個方法中包含了 "建立 bean 實例"、"將實例緩存到單例緩存池中" 這兩個邏輯。

咱們先假設已經成功建立出 bean 實例了,先去看看把實例放入緩存池的代碼 —— getSingleton():

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(beanName, "Bean name must not be null");
    synchronized (this.singletonObjects) {
    	Object singletonObject = this.singletonObjects.get(beanName);
    	if (singletonObject == null) {
            // ... 省略邏輯咱們不須要太關心, 就是一些前置、後置處理
            
            // 這裏就會獲取到單例bean的對象
            // 也就是經過lambda表達式中方法的返回值中獲取到單例bean實例
            try {
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            }
            
            // 關鍵是這裏, 會將惟一標識、單例bean對象放入到緩存中
            if (newSingleton) {
            	addSingleton(beanName, singletonObject);
            }
    	}
    	// 最後把這個單例bean實例給返回
    	return singletonObject;
    }
}
複製代碼

咱們深刻一下單例 bean 建立實例,也就是lambda表達式中的代碼:java createBean(beanName, mbd, args); 的執行過程:

AbstractAutowireCapableBeanFactory.createBean()

AbstractAutowireCapableBeanFactory 這個類一樣是 DefaultListableBeanFactory 的父類:

/** * Central method of this class: creates a bean instance, * populates the bean instance, applies post-processors, etc. * @see #doCreateBean */
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
    // ... 省略掉其餘的邏輯, 只關心建立實例的邏輯
    
    try {
        // 這裏又調用了一個 doCreateBean() 方法
    	Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    	if (logger.isTraceEnabled()) {
    		logger.trace("Finished creating instance of bean '" + beanName + "'");
    	}
    	return beanInstance;
    }
    catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
    	// A previously detected exception with proper bean creation context already,
    	// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
    	throw ex;
    }
    catch (Throwable ex) {
    	throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
    }
}
複製代碼

咱們繼續深刻到 doCreateBean() 內部的邏輯:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {

    // ... 省略掉一些代碼
    
    if (instanceWrapper == null) {
        // 這裏就是bean真正建立的方法
        // 傳入惟一標識、BeanDefinition、參數
    	instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    
    // ... 省略掉一些代碼
    
    return exposedObject;
}
複製代碼

繼續深刻到 createBeanInstance()

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    // 省略掉其他代碼
    
    if (resolved) {
    	if (autowireNecessary) {
            return autowireConstructor(beanName, mbd, null, null);
    	}
    	else {
    	    // 經過惟一標識、bean定義去實例化bean
            return instantiateBean(beanName, mbd);
    	}
    }

    // 省略掉其他代碼
}
複製代碼

繼續深刻到 instantiateBean()

protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
    try {
        //...
    	
    	else {
    	    // 注意這裏的 instantiate 方法, 繼續跟進
            beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
    	}
    	
    	//...
    }
    catch (Throwable ex) {
    	throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
    }
}
複製代碼

繼續深刻 instantiate()

@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
    // Don't override the class with CGLIB if no overrides.
    if (!bd.hasMethodOverrides()) {
    	Constructor<?> constructorToUse;
    	synchronized (bd.constructorArgumentLock) {
            constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
            if (constructorToUse == null) {
                final Class<?> clazz = bd.getBeanClass();
                if (clazz.isInterface()) {
                    throw new BeanInstantiationException(clazz, "Specified class is an interface");
                }
                try {
                    if (System.getSecurityManager() != null) {
                    	constructorToUse = AccessController.doPrivileged(
                    			(PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
                    }
                    else {
                        // 獲取到構造方法對象
                    	constructorToUse = clazz.getDeclaredConstructor();
                    }
                    bd.resolvedConstructorOrFactoryMethod = constructorToUse;
                }
                catch (Throwable ex) {
                    throw new BeanInstantiationException(clazz, "No default constructor found", ex);
                }
            }
    	}
    	// 經過 BeanUtils.instantiateClass() 進行實例化
    	// 經過反射的方式進行一個實例化
    	return BeanUtils.instantiateClass(constructorToUse);
    }
    else {
    	// Must generate CGLIB subclass.
    	return instantiateWithMethodInjection(bd, beanName, owner);
    }
}
複製代碼

2、總結

經過這篇文章的分析,咱們必需要明確如下幾個關鍵點:

  • Spring 在獲取單例對象的實例時,會先嚐試從緩存池獲取,這個緩存池底層經過了 ConcurrentHashMap 進行實現。
  • 若是緩存池中沒有,那麼會獲取到 beanDefinition,而後經過這個 beanDefinition 進行實例的建立。
  • 當建立成功後會放入緩存池中,並返回相應的實例。

就哪怕我分析的代碼一點都沒看懂也不要緊,這幾個點是必需要明確的。

那麼下一篇,將帶來 Spring Bean 建立策略的一個詳細分析。

相關文章
相關標籤/搜索