AbstractBeanFactory的層次結構
一. AbstractBeanFactory的作用
- api裏是這樣說的,是抽象BeanFactory的基類,同時實現了ConfigurableBeanFactory的SPI,提供了所有的功能
- 也可以從我們定義的資源中resource中來獲取bean的定義.
- 也提供了單例bean的緩存通過DefaultSingletonBeanRegistry,同時提供了單例和多例和別名的定義等操作.
- 上述只是其中的一部分,總之來說它的作用還是挺大的.
二 源碼閱讀
先介紹實現了BeanFactory接口的getBean()方法,該方法調用了doGetBean()方法獲取指定名稱的bean
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
代碼如下
/**
* Return an instance, which may be shared or independent, of the specified bean.
* @param name the name of the bean to retrieve
* @param requiredType the required type of the bean to retrieve
* @param args arguments to use when creating a bean instance using explicit arguments
* (only applied when creating a new instance as opposed to retrieving an existing one)
* @param typeCheckOnly whether the instance is obtained for a type check,
* not for actual use
* @return an instance of the bean
* @throws BeansException if the bean could not be created
*/
@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;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
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 + "'");
}
}
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 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);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
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);
}
}
}
// Create bean instance.
if (mbd.isSingleton()) {
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, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
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;
}
}
// Check if required type matches the type of the actual bean instance.
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.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
Bean的加載經歷了一個相當複雜的過程,總結下bean加載過程的大致步驟如下:
(1)轉換對應的beanName
或許很多人不理解轉換對應beanName是什麼意思,傳入的參數name不就是beanName嗎?其實不一定,這裏傳入的name有可能是別名,也可能是FactoryBean,所以需要進行一系列的解析,這些解析內容包括如下內容:
i.去除FactoryBean的修飾符,也就是如果name="&aa",那麼會首先去除&,而是name="aa"。
ii.取指定alias所表示的最終beanName,例如別名A指向名稱爲B的bean則返回B,若別名A指向別名B,別名B又指向名稱爲C的bean則返回C
(2)嘗試從緩存中加載單例
單例在Spring的同一個容器內只會被創建一次,後續再獲取bean,就直接從單例緩存中獲取了。當然這裏也只是嘗試加載,首先嚐試從緩存中加載,如果加載不成功則再次嘗試從singletonFactories中加載。因爲在創建單例bean的時候會存在依賴注入的情況,而在創建依賴的時候爲了避免循環依賴,在Spring中創建bean的原則是不等bean創建完成就會創建bean的ObjectFactory提早曝光加入到緩存中,一旦下一個bean創建時候需要依賴上一個bean則直使用ObjectFactory。
(3)bean的實例化
如果從緩存中得到了bean的原始狀態,則需要對bean進行實例化。這裏有必要強調一下,緩存中記錄的只是最原始的bean狀態,並不一定是我們最終想要的bean。舉個例子,加入我們需要對工廠bean進行處理,那麼這裏得到的其實是工廠bean的初始狀態,但是我們真正需要的是工廠bean中定義的factory-method方法返回的bean,而getObjectForBeanInstance就是完成這個工作的。
(4)原型模式的依賴檢查
只有在單例情況下才會嘗試解決循環依賴,spring解決循環依賴的辦法是通過三級緩存來解決的,這個後面再分析,如果存在A中有B屬性,B中有A屬性,那麼當依賴注入的時候,就會產生當A還未創建完的時候因爲對於B的創建再次返回創建A,造成循環依賴,也就是情況:isPrototypeCurrentInCreation(beanName)==true。
(5)檢測parentBeanFactory
從代碼上看,如果緩存沒有數據的話直接轉到父類工廠上去加載了,這是爲什麼呢?
可能我們忽略了一個很重要的判斷條件:parentBeanFactory != null && !containsBeanDefinition(beanName),parentBean如果爲空,則一切免談,這個顯而易見。但是containBeanDefinition(beanName)就比較重要了,它是檢測如果當前加載的XML配置文件中不包含beanName所對應的配置,就只能到parentBeanFactory去嘗試下了,然後再去遞歸的調用getBean方法。
(6)將存儲XML配置文件的GenericBeanDefinition轉換爲RootBeanDefinition。
因爲從XML配置文件中讀取到的Bean信息是存儲在GenericBeanDefinition中的,但是所有的Bean後續處理都是針對於RootBeanDefinition的,所以這裏需要進行一個轉換,轉換的同時如果父類bean不爲空的話,則會一併合併父類的屬性。
(7)尋找依賴
因爲bean的初始化過程中很可能會用到某些屬性,而某些屬性很可能是動態配置的,並且配置成依賴於其他的bean,那麼這個時候就有必要先加載依賴的bean,所以在Spring的加載順序中,在初始化某一個bean的時候首先會初始化這個bean所對應的依賴。
(8)針對不同的scope進行bean的創建
我們都知道,在Spring中存在着不同的scope,其中默認的是singleton,但是還有些其他的配置諸如prototype、request、session之類的。在這個步驟中,Spring會根據不同的配置進行不同的初始化策略。
(9)類型轉換
程序到這裏返回bean後已經基本結束了,通常對該方法的調用參數requiredType是爲空的,但是可能會存在這樣的情況,返回的bean其實是個String,但是requiredType卻傳入Integer類型,那麼這個時候本步驟就會起作用了,他的功能是將返回的bean轉換爲requiredType所指定的類型。
經過上面的步驟後bean的加載就結束了,這個時候就可以返回我們所需要的bean了,
上面代碼是spring如何獲取bean的過程,實際最核心的是createBean() 方法,該方法真正的創建bean的過程
/**
* 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 {
if (logger.isTraceEnabled()) {
logger.trace("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
// Make sure bean class is actually resolved at this point, and
// clone the bean definition in case of a dynamically resolved Class
// which cannot be stored in the shared merged bean definition.
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
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()的實現
/**
* Actually create the specified bean. Pre-creation processing has already happened
* at this point, e.g. checking {@code postProcessBeforeInstantiation} callbacks.
* <p>Differentiates between default bean instantiation, use of a
* factory method, and autowiring a constructor.
* @param beanName the name of the bean
* @param mbd the merged bean definition for the bean
* @param args explicit arguments to use for constructor or factory method invocation
* @return a new instance of the bean
* @throws BeanCreationException if the bean could not be created
* @see #instantiateBean
* @see #instantiateUsingFactoryMethod
* @see #autowireConstructor
*/
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
1、緩存中獲取單例bean
前面已經提到過,單例在Spring的同一個容器內只會被創建一次,後續再獲取bean直接從單例緩存中獲取,當然這裏也只是嘗試加載,首先嚐試從緩存中加載,然後再次嘗試從singletonFactories中加載。因爲在創建單例bean的時候會存在依賴注入的情況,而在創建依賴的時候爲了避免循環依賴,Spring創建bean的原則是不等bean創建完成就會將創建bean的ObjectFactory提早曝光加入到緩存中,一旦下一個bean創建時需要依賴上個bean,則直接使用ObjectFactory。
看下getSingleton()方法
/**
* Return the (raw) singleton object registered under the given name.
* <p>Checks already instantiated singletons and also allows for an early
* reference to a currently created singleton (resolving a circular reference).
* @param beanName the name of the bean to look for
* @param allowEarlyReference whether early references should be created or not
* @return the registered singleton object, or {@code null} if none found
*/
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
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;
}
這個方法因爲涉及循環依賴的檢測,以及涉及很多變量的記錄存取,所以讓人摸不着頭腦。這個方法首先嚐試從singletonObjects裏面獲取實例,如果獲取不到再從earlySingletonObjects裏面獲取,如果還獲取不到,再嘗試從singletonFactories裏面獲取beanName對應的ObjectFactory,然後調用這個ObjectFactory的getObject來創建bean,並放到earlyReferenceObjects裏面去,並且從singletonFactories裏面remove掉ObjectFactory,而對於後續的所有內存操作都只爲了循環依賴檢測時候使用,也就是allowEarlyReference爲true的情況下使用。
這裏涉及用於存儲bean的不同的map,可能會讓我們感到崩潰,簡單的解析一下:
- singletonObjects:用於保存BeanName和創建bean實例之間的關係,bean name --> bean instance
- singletonFactories:用於保存BeanName和創建bean的工廠之間的關係,bean name --> ObjectFactory。與earlySingletonObjects互斥
- earlySingletonObjects:也是保存BeanName和創建bean實例之間的關係,與singletonObjects不同的地方在於,當一個單例bean被放到這裏面後,那麼當bean還在創建過程中就可以通過getBean獲得了,其目的是用來檢測循環引用。與singletonFactories互斥
- registeredSingletons:用來保存當前所有已註冊的bean
2、從bean的實例獲取對象
在getBean方法中,getObjefctForBeanInstance是個高頻率使用的方法,無論是從緩存中獲得bean還是根據不同的scope策略加載bean。總之,我們得到bean的實例後要做的第一步就是調用這個方法來檢測一下正確性,其實就是用於檢測當前bean是否是FactoryBean類型的bean,如果是,那麼需要調用該bean對應的FactoryBean實例中的getObject方法作爲返回值
無論是從緩存中獲取到的bean還是通過不同的scope策略加載的bean都只是最原始的bean狀態,並不一定是我們最終想要的bean。舉個例子,假如我們需要對工廠bean進行處理,那麼這裏得到的其實是工廠bean的初始狀態,但是我們真正需要的是工廠bean中定義的factory-method方法返回的bean,而getObjectForBeanInstance方法就是幹這個工作的。
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
//如果指定的name是工廠相關(以&爲前綴)
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
//如果beanInstance不是FactoryBean類型,則拋出異常
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
}
//現在我們有了一個bean實例,這個實例可能是FactoryBean也可能是正常的bean,
//如果是FactoryBean我們使用創建實例,但是如果用戶想要直接獲取工廠實例而不是工廠getObject所對應的實例
//那麼傳入的name應該加前綴&
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
//剩下的就是FactoryBean且是需要返回FactoryBean的getObject方法所對應的實例
Object object = null;
if (mbd == null) {
//嘗試從緩存中加載bean
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
//containsBeanDefinition檢測beanDefinitionMap中也就是所有已經加載的類中檢測是否定義benaName
if (mbd == null && containsBeanDefinition(beanName)) {
//將存儲XML配置文件的GenericBeanDefinition轉換爲RootBeanDefintion,如果指定BeanName是子Bean的話同時合併父類的相關屬性
mbd = getMergedLocalBeanDefinition(beanName);
}
//是否是用戶定義的而不是應用程序本身定義的
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
從上面的代碼來看,其實這個方法並沒有什麼重要的信息,大多是些輔助代碼以及一些功能性的判斷,而真正核心的代碼卻委託給了getObjectFromFactoryBean,我們來看看getObjectForBeanInstance所做的工作
(1)對FactoryBean正確性的驗證
(2)對非FactoryBean不做任何處理
(3)對bean進行轉換
(4)將從Factory中解析bean的工作委託給getObjecFromFactoryBean
我們下面來看看getObjectFromFactoryBean方法的內容
package org.springframework.beans.factory.support;
public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry {
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
//如果是單例模式
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
//嘗試從緩存中獲取BeanName對應的實例
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
object = doGetObjectFromFactoryBean(factory, beanName);
//判斷是否在獲取object期間已經在緩存中存儲了BeanName對應的實例
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);
}
}
//將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進行後處理。下面我們看一下後處理代碼
package org.springframework.beans.factory.support;
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
return applyBeanPostProcessorsAfterInitialization(object, beanName);
}
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
}
對於後處理器的使用我們還未過多接觸,後續文章會使用大量篇幅介紹,這裏,我們只需要瞭解在Spring獲取bean的規則中有這樣一條:儘可能保證所有bean初始化後都會調用註冊的BeanPostProcessor的postProcessAfterInitialization方法進行處理,在實際的開發中大可以針對此特性設計自己的業務邏輯。
在doGetObjectFromFactoryBean方法中我們終於看到了我們想要看到的方法,也就是factory.getObject(),我們下面來看一下
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方法創建實例
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);
}
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;
}
3、獲取單例
之前講解了從緩存中獲取單例的過程,那麼,如果緩存中不存在已經加載的單例bean就需要從頭開始bean的加載過程了。而spring中使用getSingleton的重載方法實現bean的加載過程。下面我們來看一看代碼:
/**
* Return the (raw) singleton object registered under the given name,
* creating and registering a new one if none registered yet.
* @param beanName the name of the bean
* @param singletonFactory the ObjectFactory to lazily create the singleton
* with, if necessary
* @return the registered singleton object
*/
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) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
上述代碼其實是使用了回調方法,使得程序可以在單例中創建的前後做一些準備級處理操作,而真正獲取單例bean的方法其實並不是在此方法中實現的,其實現邏輯是在ObjectFactory類型的實例singletonFactory的getObject方法中實現的。而這些準備及處理操作包括如下內容。
(1)檢查緩存是否已經加載過
(2)若沒有加載,則記錄beanName的正在加載狀態
(3)加載單例前記錄加載裝態
可能你會覺得beforeSingletonCreation方法是個空實現,裏面沒有任何邏輯,但其實不是,這個函數中做了一個很重要的操作:記錄加載狀態,也就是通過this.singletonCurrentlyInCreation.add(beanName)將正要創建的bean記錄在緩存中,這樣便可以對循環依賴進行檢測,下面是代碼:
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
(4)通過調用參數傳入的ObjectFactory的個體Object方法實例化bean
(5)加載單例後的處理方法調用。同步驟(3)記錄加載狀態相似,當bean加載結束後需要移除緩存中對該bean的正在加載狀態的記錄。下面是代碼:
protected void afterSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
}
(6)將結果記錄至緩存並刪除加載bean過程中所記錄的各種輔助狀態。下面是代碼:
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
(7)返回結果處理。
雖然我們已經從外部瞭解了加載bean的邏輯結構,但現在我們還並沒有開始對bean加載功能的探索,之前提到過,bean的加載邏輯其實是在傳入的ObjectFactory類型的singletonFactory中定義的,我們反推參數的獲取,得到如下代碼
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
ObjectFactory的核心部分其實只是調用了createBean的方法,所以我們還需要到createBean方法中追尋真理。
4、準備創建Bean
我們不可能指望在一個函數中完成一個複雜的邏輯,而且我們跟蹤了這麼多的Spring代碼,經歷了這麼多的函數,或多或少也發現了一些規律:一個真正幹活的函數其實都是以do開頭的,比如doGetObjectFromFactoryBean;而給我們錯覺的函數,比如getObjectFromFactoryBean其實只是從全局角度去做些統籌的工作。這個規則對於createBean也不例外,那麼讓我們看看在createBean函數中都做了哪些準備工作。
createBean()在其抽象子類AbstractAutowireCapableBeanFactory.java中實現,代碼如下:
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
//鎖定class,根據設置的class屬性或者className解析class
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
//驗證及準備覆蓋的方法,4.1
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
//給BeanPostProcessors一個機會來返回代理來代替真正的實例,4.2
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
//創建bean實例
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("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);
}
}
從代碼我們可以總結出函數完成的具體步驟及功能
(1)根據設置的class屬性或者根據className來解析Class
(2)對override屬性進行標記和驗證。我們知道在Spring中是沒有override-method這樣的配置的,但是Spring配置中是存在lookup-method和replace-method的,而這兩個配置的加載其實就是將配置統一存放在BeanDefinition中的methodOverrides屬性裏,而這個函數的操作 就是針對於這兩個配置的。
(3)應用初始化前的後處理器,解析bean是否存在初始化前的短路操作
(4)創建bean
4.1、處理override屬性
我們首先看下AbstractBeanDefinition.java中定義的prepareMethodOverride()方法,對override屬性標記及驗證的邏輯實現的代碼:
public void prepareMethodOverrides() throws BeanDefinitionValidationException {
//判斷是否overrideMethods中是否存在需要覆蓋的方法
if (hasMethodOverrides()) {
Set<MethodOverride> overrides = getMethodOverrides().getOverrides();
//同步全局變量
synchronized (overrides) {
for (MethodOverride mo : overrides) {
prepareMethodOverride(mo);
}
}
}
}
//真正實現覆蓋方法的方法
protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
//獲取對應類中對應方法名的個數
int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
if (count == 0) {
throw new BeanDefinitionValidationException(
"Invalid method override: no method with name '" + mo.getMethodName() +
"' on class [" + getBeanClassName() + "]");
}
else if (count == 1) {
//標記MethodOverrides暫未被覆蓋,避免參數類型檢查的開銷
mo.setOverloaded(false);
}
}
通過上面兩個函數的代碼我們可以很清楚的看到Spring對於lookup-method和replace-method這兩個配置的處理過程。前面我們知道,這兩個配置屬性是統一存放在了BeanDefinition的methodOverrides屬性裏,這兩個功能的實現原理其實就是在bean實例化的時候如果檢測到存在methodOverrides屬性,會動態的爲當前bean生成代理並使用對應的攔截器爲bean做增強處理,相關邏輯實現在bean的實例化部分詳細介紹。
但是,這裏要提到的一點是,對於方法的匹配來講,如果一個類中存在若干個重載方法,那麼,在函數調用及增強的時候還需要根據參數類型進行匹配,來最終確認當前調用的到底是哪個函數。但是,Spring將一部分匹配工作在這裏完成了,如果當前類中的方法只有一個,那麼就設置重載該方法沒有被重載,這樣在後續調用的時候便可以直接使用找到的方法,而不需要進行方法的參數匹配驗證了,而且還可以對方法的存在性進行驗證,正可謂一箭雙鵰。
4.2、實例化的前置處理
在處理完overrideMethods屬性後,我們可以看到Spring的代碼中使用了這樣的一個方法resolveBeforeInstantiation(beanName, mbd)對BeanDefinition中的屬性做些前置處理。當然,無論其中是否有相應的邏輯實現我們都可以理解,因爲真正邏輯實現前後留有處理函數也是可擴展的一種體現,但是,這並不是最重要的,在函數中還提供了一個短路判斷,這纔是最爲關鍵的部分。
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
當經過前置處理後返回的結果如果不爲空,那麼會直接略過後續的Bean的創建而直接返回結果。這一特性雖然很容易被忽略,但是卻起着至關重要的作用,我們熟知的AOP功能就是基於這裏判斷的。下面我們來看一下前置處理方法的代碼:
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
此方法中最吸引我們的無疑是兩個方法:applyBeanPostProcessorsBeforeInstantiation以及applyBeanPostProcessorsAfterInstantiation。兩個方法實現的非常簡單,無非是對後處理器中的所有InstantiationAwareBeanPostProcess類型的後處理器進行postProcessBeforeInstantiation方法和BeanPostProcess的postProcessAfterInitialization方法的調用
(一)實例化前後處理器的調用
bean的實例化前調用,也就是將AbstractBeanDefinition轉化爲BeanWrapper前的處理。給子類一個修改BeanDefinition的機會,也就是說當程序經過這個方法後,bean可能已經不是我們認爲的bena了,而是或許成爲一個經過處理的代理bean,可能是通過cglib生成的,也可能是通過其他技術生成的。這個在後面會詳細介紹,我們只需要知道,在bean的實例化前會調用後處理器的方法進行處理。下面是代碼:
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
}
}
return null;
}
(二)實例化後的後處理應用
在講解從緩存中獲取單例bean的時候就提到過,Spring中的規則是在bean的初始化後儘可能保證將註冊的後處理器的postProcessAfterInitialization方法應用到該bean中,因爲如果返回的bean不爲空,那麼便不會再次經歷普通的bean的創建過程,所以只能在這裏應用後處理器的postProcessAfterInitialization方法。下面是代碼:
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
4.3循環依賴
5、創建Bean
在經歷了resolveBeforeInstantiation方法後,程序有兩個選擇,如果創建了代理或者說重寫了InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法並在方法postProcessBeforeInstantiation中改變了bean,則直接返回就可以了,否則需要進行常規bean的創建,而常規bean的創建就是在AbstractAutowireCapableBeanFactory.java中定義的doCreateBean中完成的。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
//清除緩存1
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//根據指定bean使用對應的策略創建新的實例,如:工廠方法、構造函數自動注入、簡單初始化2
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
//3bean合併處理,Autowired註解正是通過此方法實現諸如類型的預解析
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
//4.依賴處理
//是否需要提早曝光:單例&允許循環依賴&當前bean正在創建中,檢測循環依賴
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//爲避免後期循環依賴,可以在bean初始化完成前將創建實例的ObjectFactory加入工廠
//對bean的再一次依賴引用,主要應用SmartInstantiationAwareBeanPostProcessor,其中我們熟知的AOP
//就是在這裏將advice動態織入到bean中,若沒有則直接返回bean,不做任何處理
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
//5.對bean進行填充,將各個屬性值注入,其中可能存在依賴於其他bean的屬性,則會遞歸初始依賴bean
populateBean(beanName, mbd, instanceWrapper);
//調用初始化方法,比如init-method
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
//6.循環依賴檢查
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
//earlySingletonReference只有在檢測到有循環依賴的情況下才會不爲空
if (earlySingletonReference != null) {
//如果exposedObject沒有在初始化方法中被改變,也就是沒有被增強
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
//檢測依賴
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
//因爲bean創建後其所依賴的bean一定是已經創建的,actualDependentBeans不爲空則表示當前bean創建後其依賴的bean卻沒有
//全部創建完,所以說存在循環依賴
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
//7.根據scope註冊bean
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
儘管日誌與異常的內容非常重要,但是在閱讀源碼的時候似乎大部分人都會直接忽略掉。在此不深入討論日誌及異常的設計,我們看看整個函數的概要思路。
(1)如果是單例則需要首先清除緩存
(2)實例化bean,將BeanDefinition轉換爲BeanWrapper :轉換是一個複雜的過程,但是我們可以嘗試概括大致的功能,如下所示
i.如果存在工廠方法則使用工廠方法進行初始化
ii.一個類有多個構造函數,每個構造函數都有不同的的參數,所以需要根據參數鎖定構造函數並進行初始化
iii.如果既不存在工廠方法也不存在帶有參數的構造方法,則使用默認的構造函數進行bean的實例化
(3)MergedBeanDefinitionPostProcessor的應用:bean合併後的處理,Autowired註解正是通過此方法實現諸如類型的預解析
(4)依賴處理:在Spring中會有循環依賴的情況,例如,當A中含有B屬性,而B中又含有A的屬性時就會構成一個循環依賴,此時如果A和B都是單例的,那麼Spring中的處理方式就是當創建B時,涉及自動注入A的步驟時,並不是直接去再次創建A,而是通過放在緩存中的ObjectFactory來創建實例,這樣就解決了循環依賴的問題。對於循環依賴的講解可以看一下這裏
(5)屬性填充:將所有屬性填充至bean的實例中
(6)循環依賴檢查:之前提到過,在Spring中解決循環依賴只對單例有效,而對於prototype的bean,Spring沒有好的解決辦法,唯一要做的就是拋出異常。在這個步驟龍裏面會檢測已經加載的bean是否已經出現了依賴循環,並判斷是否需要拋出異常。
(7)註冊DisposableBean。
(8)完成創建並返回。
可以看到上面的步驟非常的繁瑣,每一步都使用了大量的代碼來完成其功能,最複雜也是最難以理解的當屬循環依賴的處理,在真正進入doCreateBean之前,我建議大家有必要先了解一下循環依賴。
6、創建Bean的實例
當我們瞭解了循環依賴以後就可以深入分析創建bean的每個步驟了,首先我們從AbstractAutowireCapableBeanFactory.java的createBeanInstance開始
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
//解析class
Class<?> beanClass = resolveBeanClass(mbd, beanName);
//bean的方法不爲public,且不允許訪問非public方法則拋出異常
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
//如果工廠方法不爲空,則採用工廠方法初始化策略
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean...
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
//一個類中有多個構造函數,每個構造函數都有不同的參數,所以調用前需要先根據參數確定構造函數或對應的工廠方法
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
//如果已經解析過則使用解析好的構造參數方法不需要再次鎖定
if (resolved) {
if (autowireNecessary) {
//構造函數自動注入
return autowireConstructor(beanName, mbd, null, null);
}
else {
//使用默認構造函數構造
return instantiateBean(beanName, mbd);
}
}
//需要根據參數解析構造函數
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
//構造函數自動注入
return autowireConstructor(beanName, mbd, ctors, args);
}
//使用默認構造函數構造
return instantiateBean(beanName, mbd);
}
雖然代碼中實例化的細節非常複雜,但是在createBeanInstance方法中我們還是可以清晰地看到實例化的邏輯。
(1)如果在RootBeanDefinition中存在factoryMethodName屬性,或者說在配置文件中配置了factory-method,那麼Spring會嘗試使用instantiateUsingFactoryMethod(beanName, mbd, args)方法根據RootBeanDefinition中配置生成bean的實例
(2)解析構造函數並進行構造函數的實例化。因爲一個bean對應的類中可能會有多少個構造函數,而每個構造函數的參數不同,Spring在根據參數及類型去最終判斷會使用哪個構造函數進行實例化。但是,判斷的過程是個比較消耗性能的步驟,所以採用緩存機制,如果已經解析過則不需要重複解析而是直接從RootBeanDefinition中的屬性resolvedConstructorOrFactoryMethod緩存的值去取,否則需要再次解析,並將解析的結果添加至RootBeanDefinition中的屬性resolvedConstructorOrFactoryMethod中。
6.1、autowireConstructor
對於實例的創建Spring中分成了兩種情況,一種是通用的實例化,另一種是帶有參數的實例化。帶有參數的實例化過程相當複雜,因爲存在着不確定性,所以在判斷對應參數上做了大量工作。
ConstructorResolver.java
protected BeanWrapper autowireConstructor(
String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) {
return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
}
public BeanWrapper autowireConstructor(final String beanName, final RootBeanDefinition mbd,
@Nullable Constructor<?>[] chosenCtors, @Nullable final Object[] explicitArgs) {
BeanWrapperImpl bw = new BeanWrapperImpl();
this.beanFactory.initBeanWrapper(bw);
Constructor<?> constructorToUse = null;
ArgumentsHolder argsHolderToUse = null;
Object[] argsToUse = null;
//explicitArgs通過getBean方法傳入,如果getBean方法調用的時候指定方法參數那麼直接使用
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
else {
//如果在getBean方法時候沒有指定則嘗試從配置文件中解析
Object[] argsToResolve = null;
synchronized (mbd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
if (constructorToUse != null && mbd.constructorArgumentsResolved) {
//從緩存中獲取
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
//配置的構造函數參數
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
//如果緩存中存在
if (argsToResolve != null) {
//解析參數類型,如給定方法的構造函數A(int, int)則通過此方法後就會把配置中的("1", "1")轉化爲(1, 1)
//緩存中的原始也可能是最終值
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
}
}
//沒有被緩存
if (constructorToUse == null) {
// Need to resolve the constructor.
boolean autowiring = (chosenCtors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
ConstructorArgumentValues resolvedValues = null;
int minNrOfArgs;
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
}
else {
//提取配置文件中的配置的構造函數參數
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
//用於承載解析後的構造函數參數
resolvedValues = new ConstructorArgumentValues();
//能解析到的參數個數
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
// Take specified constructors, if any.
Constructor<?>[] candidates = chosenCtors;
if (candidates == null) {
Class<?> beanClass = mbd.getBeanClass();
try {
candidates = (mbd.isNonPublicAccessAllowed() ?
beanClass.getDeclaredConstructors() : beanClass.getConstructors());
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Resolution of declared constructors on bean Class [" + beanClass.getName() +
"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
}
}
//排序給定的構造函數,public構造函數優先參數數量降序,非public構造函數參數數量降序
AutowireUtils.sortConstructors(candidates);
int minTypeDiffWeight = Integer.MAX_VALUE;
Set<Constructor<?>> ambiguousConstructors = null;
LinkedList<UnsatisfiedDependencyException> causes = null;
for (Constructor<?> candidate : candidates) {
Class<?>[] paramTypes = candidate.getParameterTypes();
if (constructorToUse != null && argsToUse.length > paramTypes.length) {
//如果已經找到選用的構造函數或者需要的參數個數小於當前構造函數參數個數則終止,因爲是參數個數降序排列
break;
}
if (paramTypes.length < minNrOfArgs) {
//參數個數不相等
continue;
}
ArgumentsHolder argsHolder;
if (resolvedValues != null) {
//有參數則根據值構造對應參數類型的參數
try {
//註釋上獲取參數名稱
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
if (paramNames == null) {
//獲取參數名稱探索器
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
//獲取指定構造函數的參數名稱
paramNames = pnd.getParameterNames(candidate);
}
}
//根據名稱和數據類型創建參數持有者
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
getUserDeclaredConstructor(candidate), autowiring);
}
catch (UnsatisfiedDependencyException ex) {
if (this.beanFactory.logger.isTraceEnabled()) {
this.beanFactory.logger.trace(
"Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);
}
// Swallow and try next constructor.
if (causes == null) {
causes = new LinkedList<>();
}
causes.add(ex);
continue;
}
}
else {
// Explicit arguments given -> arguments length must match exactly.
if (paramTypes.length != explicitArgs.length) {
continue;
}
//構造函數沒有參數的情況
argsHolder = new ArgumentsHolder(explicitArgs);
}
//探測是否有不確定性的構造函數存在,例如不同構造函數的參數爲父子關係
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
//如果它代表當前最接近的匹配則選擇作爲構造函數
if (typeDiffWeight < minTypeDiffWeight) {
constructorToUse = candidate;
argsHolderToUse = argsHolder;
argsToUse = argsHolder.arguments;
minTypeDiffWeight = typeDiffWeight;
ambiguousConstructors = null;
}
else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
if (ambiguousConstructors == null) {
ambiguousConstructors = new LinkedHashSet<>();
ambiguousConstructors.add(constructorToUse);
}
ambiguousConstructors.add(candidate);
}
}
if (constructorToUse == null) {
if (causes != null) {
UnsatisfiedDependencyException ex = causes.removeLast();
for (Exception cause : causes) {
this.beanFactory.onSuppressedException(cause);
}
throw ex;
}
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Could not resolve matching constructor " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
}
else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Ambiguous constructor matches found in bean '" + beanName + "' " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
ambiguousConstructors);
}
if (explicitArgs == null) {
//將解析的構造函數加入緩存
argsHolderToUse.storeCache(mbd, constructorToUse);
}
}
try {
final InstantiationStrategy strategy = beanFactory.getInstantiationStrategy();
Object beanInstance;
if (System.getSecurityManager() != null) {
final Constructor<?> ctorToUse = constructorToUse;
final Object[] argumentsToUse = argsToUse;
beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
strategy.instantiate(mbd, beanName, beanFactory, ctorToUse, argumentsToUse),
beanFactory.getAccessControlContext());
}
else {
beanInstance = strategy.instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
}
//將構建的實例加入BeanWrapper
bw.setBeanInstance(beanInstance);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean instantiation via constructor failed", ex);
}
}
邏輯很複雜,函數代碼量很大,包含着很多的邏輯實現,所以我們還是總覽一下整個函數,其實現的功能考慮了一下幾個方面
(1)構造函數參數的確定。
- 根據explicitArgs參數類型判斷
如果傳入的參數explicitArgs不爲空,那邊可以直接確定參數,因爲explicitArgs參數是在調用Bean的時候用戶指定的,在BeanFactory中存在這樣的方法:
Object getBean(String name, Object ... args) throws BeansException;
在獲取bean的時候,用戶不但可以指定bean的名稱,還可以指定bean所對應類的構造函數或者工廠方法的方法參數,主要用於靜態工廠方法的調用,而這裏是需要給定完全匹配的參數的,所以,便可以判斷,如果傳入參數explicitArgs不爲空,則可以確定構造函數參數就是它。對應代碼:
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
- 緩存中獲取
除此之外,確定參數的辦法如果之前分析過,也就是說構造函數參數已經記錄在緩存中,那麼便可以直接拿來使用。而且,這裏要提到的是,在緩存中緩存的可能是參數的最終類型也可能是參數的初始類型,例如:構造函數參數要求的說是int類型,但是原始的參數值可能是String類型的“1”,那麼即使緩存中得到了參數,也需要經過類型轉換器的過濾以確保參數類型與對應的構造函數參數類型完全對應。對應代碼:
else {
Object[] argsToResolve = null;
synchronized (mbd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
if (constructorToUse != null && mbd.constructorArgumentsResolved) {
// Found a cached constructor...
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
if (argsToResolve != null) {
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
}
}
- 配置文件獲取
如果不能根據傳入的參數explicitArgs確定構造函數參數,也無法從緩存中得到相關信息,那麼只能開始新一輪的分析了。
分析從獲取配置文件中配置的構造函數信息開始,經過之前的分析,我們知道,Spring中配置文件的信息經過轉換都會通過BeanDefinition實例承載,也就是mbd中包含,那麼可以通過調用mbd.getConstructorArgumentValues()來獲取配置的構造函數信息。有了配置中的信息便可以獲取對應的參數值信息了,獲取參數值的信息包括直接指定值,如:直接指定構造函數中摸個值爲原始類型String類型,或者是對其他bean的引用,而這一處理委託給resolvedConstructorArguments方法,並返回能解析到的參數的個數。代碼如下:
if (constructorToUse == null) {
// Need to resolve the constructor.
boolean autowiring = (chosenCtors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
ConstructorArgumentValues resolvedValues = null;
int minNrOfArgs;
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
}
else {
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
resolvedValues = new ConstructorArgumentValues();
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
(2)構造函數的確定。
經過了第一步已經確定了構造函數的參數,接下來的任務就是根據構造函數參數在所有構造函數中鎖定對應的構造函數,而匹配的方法就是根據參數個數匹配,所以在匹配之前需要先對構造函數按照public構造函數優先參數數量降序、非public構造函數參數數量降序。這樣可以在遍歷的情況下迅速判斷排在後面的構造函數參數個數是否符合條件。
由於在配置文件中並不是唯一限制使用參數位置索引的方式去創建,同樣還支持指定參數名稱進行設定參數值的情況,如:<constructor-arg name="aa">,那麼這種情況就需要首先確定構造函數中的參數名稱。
獲取參數名稱可以有兩種方式,一種是通過註解的方式直接獲取,另一種是使用Spring中提供的工具類ParameterNameDiscover來獲取。構造函數、參數名稱。名稱參數、參數類型、參數值都確定後就可以鎖定構造函數以及轉換對應的參數類型了。代碼如下:
AutowireUtils.sortConstructors(candidates);
int minTypeDiffWeight = Integer.MAX_VALUE;
Set<Constructor<?>> ambiguousConstructors = null;
LinkedList<UnsatisfiedDependencyException> causes = null;
for (Constructor<?> candidate : candidates) {
Class<?>[] paramTypes = candidate.getParameterTypes();
if (constructorToUse != null && argsToUse.length > paramTypes.length) {
// Already found greedy constructor that can be satisfied ->
// do not look any further, there are only less greedy constructors left.
break;
}
if (paramTypes.length < minNrOfArgs) {
continue;
}
(3)根據確定的構造函數轉換對應的參數類型。代碼如下:
if (resolvedValues != null) {
try {
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
if (paramNames == null) {
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
paramNames = pnd.getParameterNames(candidate);
}
}
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
getUserDeclaredConstructor(candidate), autowiring);
}
catch (UnsatisfiedDependencyException ex) {
if (this.beanFactory.logger.isTraceEnabled()) {
this.beanFactory.logger.trace(
"Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);
}
// Swallow and try next constructor.
if (causes == null) {
causes = new LinkedList<>();
}
causes.add(ex);
continue;
}
}
else {
// Explicit arguments given -> arguments length must match exactly.
if (paramTypes.length != explicitArgs.length) {
continue;
}
argsHolder = new ArgumentsHolder(explicitArgs);
}
主要是使用Spring中提供的類型轉換器或者用戶提供的自定義類型轉換器進行轉換。
(4)構造函數不確定性的驗證。
當然,有時候即使構造函數、參數名稱、參數類型都確定後也不一定會直接鎖定構造函數,不同構造函數的參數爲父子關係,所以Spring在最後又做了一次驗證。代碼如下:
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
// Choose this constructor if it represents the closest match.
if (typeDiffWeight < minTypeDiffWeight) {
constructorToUse = candidate;
argsHolderToUse = argsHolder;
argsToUse = argsHolder.arguments;
minTypeDiffWeight = typeDiffWeight;
ambiguousConstructors = null;
}
else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
if (ambiguousConstructors == null) {
ambiguousConstructors = new LinkedHashSet<>();
ambiguousConstructors.add(constructorToUse);
}
ambiguousConstructors.add(candidate);
}
}
if (constructorToUse == null) {
if (causes != null) {
UnsatisfiedDependencyException ex = causes.removeLast();
for (Exception cause : causes) {
this.beanFactory.onSuppressedException(cause);
}
throw ex;
}
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Could not resolve matching constructor " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
}
else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Ambiguous constructor matches found in bean '" + beanName + "' " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
ambiguousConstructors);
}
if (explicitArgs == null) {
argsHolderToUse.storeCache(mbd, constructorToUse);
}
6.2、instantiateBean
經歷了帶有參數的構造函數的實例構造,再看不帶參數的構造函數的實例化過程就會變的輕鬆加愉快了,下面是代碼:
AbstractAutowireCapableBeanFactory.java
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
final BeanFactory parent = this;
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
getInstantiationStrategy().instantiate(mbd, beanName, parent),
getAccessControlContext());
}
else {
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
}
6.3、實例化策略
實例化過程中反覆提到過實例化策略,那這又是做什麼用的呢?其實經過前面的分析,我們已經得到了足以實例化的所有相關信息,完全可以使用最簡單的反射方法直接反射來構造實例對象,但是Spring卻並沒有這麼做。來看一下代碼:
SimpleInstantiationStrategy.java
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
//如果有需要覆蓋或者動態替換的方法則需要使用cglib進行動態代理,因爲可以在創建代理的同時將動態方法織入類中
//但是如果沒有需要動態改變的方法,爲了方便直接反射就可以了
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);
}
}
}
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// Must generate CGLIB subclass.
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
看了上面兩個函數後似乎我們贏感受到了Spring的用心良苦以及爲了能更方便的使用Spring而做的大量的工作。程序中,首先判斷如果beanDefinition.getMethodOverrides()爲空,也就是用戶沒有使用replace-method或者lookup-method配置,那麼直接使用反射的方法,簡單快捷,但是如果使用了這兩個特性,在直接使用反射的方法創建就有些不妥了,因爲需要將這兩個配置提供的動能切入進去,所以必須要使用動態代理的方式將包含兩個特性所對應的邏輯的攔截增強器設置進去,這樣纔可以保證在調用方法的時候會被相應的攔截器增強,返回值爲包含攔截器的代理實例。
記錄創建bean的ObjectFactory
讓我們繼續回到doCreateBean方法中,在裏面有這樣一段代碼:
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//爲避免後期循環依賴,可以在bean初始化完成前將創建實例的ObjectFactory加入工廠
//對bean的再一次依賴引用,主要應用SmartInstantiationAwareBeanPostProcessor,其中我們熟知的AOP
//就是在這裏將advice動態織入到bean中,若沒有則直接返回bean,不做任何處理
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
這段代碼不是很複雜,但是很多人不是太理解這段代碼的作用,而且,這段代碼僅從此函數中去理解也很難弄懂其中的含義,我們需要從全軍的角度去思考Spring的依賴解決辦法。
- earlySingletonExposure:從字面的意思理解就是提早曝光的單例,我們暫不定義它的學名叫什麼,我們感興趣的是有哪些條件影響這個值。
- mbd.isSingleton():沒有太多可以解釋的,此RootBeanDefinition代表的是否是單例。
- this.allowCircularReferences:是否允許循環依賴,很抱歉,並沒有找到在配置文件中如何配置,但是在AbstractRefreshableApplicationContext中提供了設置函數,可以通過硬編碼的方式進行設置或者可以通過自定義命名空間進行配置,其中硬編碼的方式代碼如下:
-
ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext("aspectTest.xml"); bf.setAllowBeanDefinitionOverriding(false);
- sSingletonCurrentlyInCreation(beanName):該bean是否在創建中。在Spring中,會有專門的屬性默認爲DefaultSingletonBeanRegistry的singletonsCurrentlyInCreation來記錄bean的加載狀態,在bean開始創建前會將beanName記錄在屬性中,在bean創建結束後會將beanName從屬性中移除。那麼我們跟隨代碼一路走來可是對這個屬性的記錄並沒有多少印象,這個狀態是從哪裏記錄的呢?不同的scope的記錄位置並不一樣,我們以singleton爲例,在singleton下記錄屬性的函數是在DefaultSingletonBeanRegistry類的getSingletone(String beanName, ObjectFactory singletonFactory)函數的beforeSingletonCreation(beanName)和afterSingletonCreation(beanName)中,在這兩段函數中分別對屬性進行了記錄和移除。
-
經過以上分析我們瞭解變量earlySingletonExposure是否爲true、是否是單例、是否允許循環依賴、是否對應的bean正在創建的條件的綜合。當這幾個條件同時滿足時會執行addSingletonFactory操作,那麼加入SingletonFactory的作用是什麼呢?又是在什麼時候調用呢?
我們還是以最簡單的AB循環爲例,類A中含有屬性類B,而類B中又會含有屬性類A,那麼初始化beanA的過程如下圖所示:
圖中展示了創建beanA的流程,圖中我們看到,在創建A的時候首先會記錄類A所對應的beanName,並將beanA的創建工廠加入緩存中,而在對A的屬性填充也就是調用populateBean方法的時候又會再一次的對B進行遞歸創建。同樣的,因爲在B中同樣存在A屬性,因此在實例化B的populate方法中又會再次的初始化B,也就是圖形的最後,調用getBean(A)。關鍵是這裏,有心的讀者可以去找找這個代碼的實現方式,我們之前已經講過,在這個函數中並不是直接去實例化A,而是先去檢測緩存中是否有已經創建好的對應的bean,或者是否已經創建好的ObjectFactory,而此時的ObjectFactory我們早已創建,所以便不會再去向後執行,而是直接調用ObjectFactory去創建A。這裏最關鍵的是ObjectFactory的實現。根據以上分析,基本可以理清Spring處理循環依賴的解決辦法,在B中創建依賴A時通過ObjectFactory提供的實例化方法來中斷A中的屬性填充,使B中持有的A僅僅是剛剛初始化並沒有填充任何屬性的A,而初始化A的步驟是在最開始創建A的時候進行的,但是因爲A與B中的A所表示的屬性地址是一樣的,所以A中創建好的屬性填充自然可以通過B中的A獲取,這樣就解決了循環依賴的問題。也正是由於ObjectFactory提供的實例是初始化狀態下的實例,所以構造器構造bean的循環依賴Spring是無法解決的,同樣,由於屬性地址的問題,在非單例模式下,兩個實例的地址不一定相同,所以Spring也無法解決這種情況下的循環依賴。
6.3、屬性注入
在瞭解循環依賴的時候,我們曾經反覆提到了populateBean這個函數,也多少了解了這個函數的主要功能就是屬性填充,那麼究竟是如何填充的呢?
AbstractAutowireCapableBeanFactory.java
protected void autowireByName(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
//尋找bw中需要依賴注入的屬性
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
if (containsBean(propertyName)) {
//遞歸初始化相關的bean
Object bean = getBean(propertyName);
pvs.add(propertyName, bean);
//註冊依賴
registerDependentBean(propertyName, beanName);
if (logger.isDebugEnabled()) {
logger.debug("Added autowiring by name from bean name '" + beanName +
"' via property '" + propertyName + "' to bean named '" + propertyName + "'");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +
"' by name: no matching bean found");
}
}
}
}
如果大家之前瞭解了autowire的使用方法,相信理解這個函數的功能不會太困難,無非是在傳入參數pvs中找出已經加載的bean,並遞歸實例化,進而加入到pvs中。
2、autowireByType
autowireByType與autowireByName對於我們理解與使用來說複雜程度都很相似,但是其實現功能的複雜度卻完全不一樣
AbstractAutowireCapableBeanFactory.java
protected void autowireByType(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
//尋找bw中需要依賴注入的屬性
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
try {
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
if (Object.class != pd.getPropertyType()) {
//探測指定屬性的set方法
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd)
boolean eager = !PriorityOrdered.class.isInstance(bw.getWrappedInstance());
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
//解析指定beanName的屬性所匹配的值,並把解析到的屬性名稱存儲在autowiredBeanNames中,當屬性存在多個封裝的bean時
//比如@Autowire private List<A> aList;將會找到所有匹配A類型的bean並將其注入
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
if (autowiredArgument != null) {
pvs.add(propertyName, autowiredArgument);
}
for (String autowiredBeanName : autowiredBeanNames) {
//註冊依賴
registerDependentBean(autowiredBeanName, beanName);
if (logger.isDebugEnabled()) {
logger.debug("Autowiring by type from bean name '" + beanName + "' via property '" +
propertyName + "' to bean named '" + autowiredBeanName + "'");
}
}
autowiredBeanNames.clear();
}
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
}
}
}
實現根據名稱自動匹配的第一步就是尋找bw中需要依賴注入的屬性,同樣對於根據類型自動匹配的實現來講第一步也是尋找bw中需要依賴注入的屬性,然後遍歷這些屬性並尋找類型匹配的bean,其中最複雜的就是尋找類型匹配的bean。同時,Spring中提供了對集合注入的支持,比如使用註解的方式:
@Autowired
private List<TestA> tests;
Spring將會把所有與Test匹配的類型找出來並注入到tests屬性中,正是由於這一因素,所以在autowireByType函數中,新建了局部遍歷autowiredBeanNames,用於存儲所有依賴的bean,如果只是對非集合類的屬性注入來說,此屬性並無用處。
對於尋找類型匹配的邏輯實現封裝在了resolveDependency函數中
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
if (Optional.class == descriptor.getDependencyType()) {
//Optional類注入的特殊處理
return createOptionalDependency(descriptor, requestingBeanName);
}
else if (ObjectFactory.class == descriptor.getDependencyType() ||
ObjectProvider.class == descriptor.getDependencyType()) {
//ObjectFactory和ObjectProvider類注入的特殊處理
return new DependencyObjectProvider(descriptor, requestingBeanName);
}
else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
//javaxInjectProviderClass類注入的特殊處理
return new Jsr330ProviderFactory().createDependencyProvider(descriptor, requestingBeanName);
}
else {
//通用處理邏輯
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
上面的的代碼的註釋中已經提到了,Spring5.0相比Spring3.0在代碼上做出的改進,將原本代碼中處理Array、Collection和Map的處理邏輯全部放進了一個新的方法resolveMultipleBeans中,這樣就避免了我們之前看到的Spring中的某些代碼過長,導致邏輯層次不是很清晰的問題。
尋找類型匹配執行順序時,首先嚐試使用解析器進行解析,如果解析器沒有成功解析,那麼可能是使用默認的解析器沒有做任何處理,或者是使用了自定義的解析器,但是對於集合類型來說並不在解析範圍之內,所以再次對不同類型進行不同情況的處理,雖說對於不同類型處理方式不太一致,但是大致的思路還是很相似的,所以函數中只對數組類型進行了詳細的註釋。
3、applyPropertyValues
程序運行到這裏,已經完成了對所有注入屬性的獲取,但是獲取的屬性是以PropertyValues形式存在的,還並沒有應用到已經實例化的bean中,這一工作是在applyPropertyValues中完成的。下面是代碼:
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
if (pvs.isEmpty()) {
return;
}
if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
}
MutablePropertyValues mpvs = null;
List<PropertyValue> original;
if (pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues) pvs;
//如果mpvs中的值已經被轉換爲對應的類型那麼可以直接設置到beanWrapper中
if (mpvs.isConverted()) {
// Shortcut: use the pre-converted values as-is.
try {
bw.setPropertyValues(mpvs);
return;
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
original = mpvs.getPropertyValueList();
}
else {
//如果pvs並不是使用MutablePropertyValues封裝的類型,那麼直接使用原始的屬性獲取方法
original = Arrays.asList(pvs.getPropertyValues());
}
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
//獲取對應的解析器
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
//深拷貝
List<PropertyValue> deepCopy = new ArrayList<>(original.size());
boolean resolveNecessary = false;
//遍歷屬性,將屬性轉換爲對應類的對應屬性的類型
for (PropertyValue pv : original) {
if (pv.isConverted()) {
deepCopy.add(pv);
}
else {
String propertyName = pv.getName();
Object originalValue = pv.getValue();
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
Object convertedValue = resolvedValue;
boolean convertible = bw.isWritableProperty(propertyName) &&
!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
if (convertible) {
convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
}
// Possibly store converted value in merged bean definition,
// in order to avoid re-conversion for every created bean instance.
if (resolvedValue == originalValue) {
if (convertible) {
pv.setConvertedValue(convertedValue);
}
deepCopy.add(pv);
}
else if (convertible && originalValue instanceof TypedStringValue &&
!((TypedStringValue) originalValue).isDynamic() &&
!(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
pv.setConvertedValue(convertedValue);
deepCopy.add(pv);
}
else {
resolveNecessary = true;
deepCopy.add(new PropertyValue(pv, convertedValue));
}
}
}
if (mpvs != null && !resolveNecessary) {
mpvs.setConverted();
}
// Set our (possibly massaged) deep copy.
try {
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
6.4、初始化bean
大家應該記得bean配置時bean中有一個init-method屬性,這個屬性的作用是在bean實例化前調用init-method指定的方法來根據用戶業務進行相應的實例化。我們現在就已經進入這個方法了,首先看一下這個方法的執行位置,Spring中程序已經執行過bean的實例化,並且進行了屬性的填充,而就在這時會調用用戶設定的初始化方法。
AbstractAutowireCapableBeanFactory.java
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
//對特殊的bean處理:Aware、BeanClassLoaderAware、BeanFactoryAware
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//應用後處理器
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
//激活用戶自定義的init方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
//後處理器的應用
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
雖說此函數的主要目的是進行客戶設定的初始化方法的調用,但是除此之外還有其他必要的工作。
6.4.1、激活Aware方法
在分析其原理之前,我們先了解一下Aware的使用。Spring中提供了一些Aware相關接口,比如BeanFactoryAware、ApplicationContextAware、ResourceLoaderAware、ServletContextAware等、實現這些Aware接口的bean在被初始之後,可以取得一些相對應的資源,例如實現BeanFactoryAware的bean在初始化後,Spring容器將會注入BeanFactory的實例,而實現ApplicationContextAware的bean,在bean被初始化後,將會被注入ApplicationContext實例等,我們首先通過示例方法來了解一下Aware的使用。
(1)定義普通bean。
public class Hello{
public void say(){
System.out.println("hello");
}
}
(2)定義BeanFactoryAware類型的bean
public class Test implements BeanFactoryAware{
private BeanFactory beanFactory;
//聲明bean的時候Spring會自動注入BeanFactory
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeanException{
this.beanFactory = beanFactory;
}
public void testAware(){
//通過hello這個bean id從beanFactory中獲取實例
Hello hello = (Hello)beanFactory.getBean("hello");
hello.say();
}
}
(3)使用main方法測試
public static void main(Stirng[] args){
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Test test = (Test)ctx.getBean("test");
test.testAware();
}
運行測試類,控制檯輸出:hello
按照上面的方法我們可以獲取到Spring中BeanFactory,並且可以根據BeanFactory獲取所有bean,以及進行相關設置。當然還有其他Aware的使用方法都大同小異,看一下,Spring的實現方式,相信大家便會使用了。下面是代碼:
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
2、處理器的應用
BeanPostProcessor相信大家都並不陌生,這是Spring中開放式架構中一個必不可少的亮點,給用戶充足的權限去更改或擴展Spring,而除了BeanPostProcessor外還有很多其他的PostProcessor,當然大部分都是以此爲基礎,繼承自BeanPostProcessor。BeanPostProcessor的使用位置就是這裏,在調用客戶之定義初始化方法前以及調用自定義初始化方法後分別會調用BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法,使用戶可以根據自己的業務需求進行響應的處理。
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
Object current = beanProcessor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
3、激活自定義的init方法
客戶定製的初始化方法除了我們熟知的使用配置init-method外,還有使自定義的bean實現InitializingBean接口,並在afterPropertiesSet中實現自己的初始化業務邏輯。
init-method與afterPropertiesSet都是在初始化bean時執行,執行順序是afterPropertiesSet先執行,而init-method後執行。在invokeInitMethods方法中就實現了這兩個步驟的初始化方法調用。
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
//首先檢查是否是InitializingBean,如果是的話需要afterPropertiesSet方法
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
//屬性初始化後處理
((InitializingBean) bean).afterPropertiesSet();
}
}
if (mbd != null && bean.getClass() != NullBean.class) {
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
//調用自定義初始化方法
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
註冊DisposableBean
Spring中不但提供了對於初始化方法的擴展入口,同樣也提供了銷燬方法的擴展入口,對於銷燬方法的擴展,除了我們熟知的配置屬性destroy-method方法外,用戶還可以註冊後處理器DestructionAwareBeanPostProcessor來統一處理bean的銷燬方法,代碼如下
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
if (mbd.isSingleton()) {
//單例模式下注冊需要銷燬的bean,此方法中會處理實現DisposableBean的bean
//並且對所有的bean使用DestructionAwareBeanPostProcessor處理
registerDisposableBean(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
else {
//自定義scope處理
Scope scope = this.scopes.get(mbd.getScope());
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
}
scope.registerDestructionCallback(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
}
}
至此,用BeanFactory方式創建和獲取bean的流程我們就徹底分析完了,但是在實際的代碼中,我們是很少會使用BeanFactory這種方式去獲取bean。通常我們使用的是ApplicationContext來獲取,這倆者究竟有什麼區別,我們又爲什麼選擇後者,這些將在下一篇文章中瞭解到。