Spring源碼解析——Bean的加載前奏
User user = (User)context.getBean("testbean");
由這句入手
AbstractBeanFactory#getBean
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
// 提取對應的 beanName
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
/**
檢查緩存中或者實例工廠中是否有對應的實例
為什么首先會使用這段代碼呢,因為在創建單例 bean 的時候會存在依賴注入的情況,
而在創建依賴的時候為了避免循環依賴,Spring 創建 bean 的原則是不等 bean 創建
完成就會將創建的 bean 的 ObjectFactory 提前曝光,也就是將 ObjectFactory 加入
緩存中,一旦下個 bean 創建時候需要依賴上個 bean 則直接使用 ObjectFactory
**/
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// 返回對應的實例,有時候存在諸如 BeanFactory 的情況并不是直接返回實例本身而是返回指定方法返回的實例
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
/**
只有在單例情況才會嘗試解決依賴循環,原型模型情況,如果存在
A 中有 B 的熟悉,B 中有 A 的屬性,那么當依賴注入的時候,就會產生當 A 還未創建完的時候
因為對于 B 的創建再次返回創建 ,造成依賴循環,也就是下面的情況
**/
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
// 如果 beanDefinitionMap 中也就是在所有已經加載的類中不包括 beanName 則
// 嘗試從 parentBeanFactory 中檢測
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
// 遞歸到 BeanFactory 中尋找
if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
// 如果不是僅僅做類型檢查則是創建 bean,這里要進行記錄
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
// 將存儲 XML 配置文件的 GernericBeanDefinition 轉換為 RootBeanDefinition,
// 如果指定 BeanName 是子 Bean 的話同時會合并父類的相關屬性
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
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);
getBean(dep);
}
}
// Create bean instance.
// 實例化依賴的 bean 后便可以實例化 mbd 本身了
// singleton 模式的創建
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
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.
// prototype 模式的創建 (new)
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
// 指定的 scope 上實例化 bean
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, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
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.
// 檢查需要的類型是否符合 bean 的實際類型
if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
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;
}
大致過程:
-
轉換對應 beanName。這里的 beanName 可能是別名,可能是 FactoryBean,所以需要一系列的解析:
- 去除 FactoryBean 的修飾符,也就是如果
name="&aa"
,那么會首先去除&
使得name=aa
- 取指定 alias 所表示的最終 beanName,例如別名 A 指向名稱為 B 的 bean 則返回 B;若別名 A 指向別名 B,別名 B 又指向名稱為 C 的 bean 則返回 C
- 去除 FactoryBean 的修飾符,也就是如果
-
嘗試從緩存中加載單例
單例在 Spring 的同一個容器內只會被創建一次,后續在獲取 bean,就直接從單例緩存中獲取了。當然這里也只是嘗試加載,首先嘗試從緩存中加載,如果加載不成功則再次嘗試從 singletonFactories 中加載。
由于存在依賴注入的問題,所以在 Spring 中創建 bean 的原則是不等 bean 創建完成就會將創建的 ObjectFactory 提早曝光加入到緩存中,一旦下一個 bean 創建需要依賴上一個 bean 則直接使用 ObjectFactory。
bean 的實例化
-
原型模式的依賴檢查
只有單例會嘗試解決循環依賴。
在非 singleton 下檢測 parentBeanFactory,看是否需要進入 parentBeanFactory 中加載(當前 BeanFactory 中無該 bean 且 parentBeanFactory 存在且存在該 bean)
將存儲 XML 配置文件的 GernericBeanDefinition 轉換為 RootBeanDefinition。方便 Bean 的后續處理。
尋找依賴
針對不同的 scope 進行 bean 的創建
類型轉換(requiredType = true)
FactoryBean 的使用
一般來說,Spring 是通過反射機制利用 bean 的 class 屬性指定實現類來實例化 bean 的。FactoryBean 是為了對付配置 bean 的復雜性的。
public interface FactoryBean<T> {
T getObject() throws Exception;
Class<?> getObjectType();
// 如果返回 true 則 getObject() 時候會將實例放入 Spring 容器中單實例緩存池中
boolean isSingleton();
}
實現了 XxxFactoryBean
之后,解析<bean id="xxx" class="xx.xx.XxxFactoryBean" />
時候會調用該其實現的 getObject()
方法
緩存中獲取單例 bean
@Override
public Object getSingleton(String beanName) {
// 設置 true 表示允許早期依賴
return getSingleton(beanName, true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 檢查緩存中是否存在實例
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 如果為空,則鎖定全局變量并進行處理
synchronized (this.singletonObjects) {
// 如果此 bean 正在加載則不處理
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 當某些方法需要提前初始化時候會調用 addSingletonFactory 方法
// 將對應的 ObjectFactory 初始化策略存儲在 singletonFactories
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 調用預先設定的 getObject 方法
singletonObject = singletonFactory.getObject();
// 記錄在緩存中,earlySingletonObjects 和 singletonFactories 互斥
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
首先嘗試從 singletonObjects
中獲取實例,如果獲取不到,則從 earlySingletonObjects
里面獲取,如果還取不到,則嘗試從 singletonFactories
里面獲取 beanName
對應的 ObjectFactory
,然后調用這個 ObjectFactory
的 getObject 來創建 bean,并放到 earlySingletonObjects
中,然后從 singletonFactories 中 remove 掉這個 ObjectFactory。
- singletonObjects: 用于保存 BeanName 和創建 bean 實例之間的關系,beanName -> beanInstance
- singletonFactories:用于保存 BeanName 和創建 bean 的工廠之間的關系,beanName -> ObjectFactory
- earlySingletonObjects:也是保存 BeanName 和創建 bean 實例之間的關系,與singletonObjects的不同之處在于,當一個單例bean被放到這里面后,那么當bean還在創建過程中,就可以通過getBean方法獲取到了,其目的是用來檢測循環引用。
- registeredSingletons:用來保存當前所有已注冊的bean。
從 bean 的實例中獲取對象
無論是從緩存中獲取到的 bean 還是通過不同的 scope 策略加載的 bean 都只是最原始的 bean 狀態,并不一定是我們最終想要的 bean。舉個例子,假如我們需要對工廠 bean 進行處理,那么這里得到的其實是工廠 bean 的初始狀態,但是我們真正需要的是工廠 bean 中定義的 factory-method 方法中返回的 bean ,而getObjectForBeanInstance
方法就是完成這個工作的。
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
// 如果指定的 name 是工廠相關(以 & 為前綴)且 beanInstance 又不是 FactoryBean 類型則驗證不通過
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
// 現在我們有了個 bean 的實例,這個實例可能會是正常的 bean 或者 FactoryBean
// 如果是 FactoryBean 我們使用它創建實例,但如果用戶想要直接獲取工廠實例而不是工程對應的
// getObject 方法對應的實例那么傳入的 name 應該包含前綴 &
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
// 加載 FactoryBean
Object object = null;
if (mbd == null) {
// 嘗試從緩存中加載 bean
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
// 到這里已經明確指定 beanInstance 一定是 FactoryBean 類型
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
// containsBeanDefinition 檢測 beanDefinitionMap 中也就是在所有已經加載的類中
// 檢測是否定義 beanName
if (mbd == null && containsBeanDefinition(beanName)) {
// 將存儲 XML 配置文件的 GernericBeanDefinition 轉換為 RootBeanDefinition,
// 如果指定 BeanName 是子 Bean 的話同時會合并父類的相關屬性
mbd = getMergedLocalBeanDefinition(beanName);
}
// 是否是用戶定義而不是應用程序本身定義的
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
- 對 FactoryBean 正確性的驗證
- 對非 FactoryBean 不做任何處理
- 對 bean 進行轉換
- 將從 Factory 中解析 bean 的工作委托給
getObjectFromFactoryBean
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
object = doGetObjectFromFactoryBean(factory, beanName);
// Only post-process and store if not put there already during getObject() call above
// (e.g. because of circular reference processing triggered by custom getBean calls)
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (object != null && shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
}
this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
}
}
return (object != NULL_OBJECT ? object : null);
}
}
else {
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (object != null && shouldPostProcess) {
try {
// 調用 ObjectFactory 的后處理器
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
這部分代碼只是做了一件事:返回的 bean 如果是單例,那就必須要保證全局唯一,同時,也因為是單例的,所以不被重復創建,可以使用緩存來提高性能,也就是說已經加載過就要記錄下來以便于下次復用,否則的話就直接獲取了。
所以我們最后是在 doGetObjectFromFactoryBean
中看到了自己想要的方法
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(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
return 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);
}
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null && isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
return object;
}
我們接下來看 doGetObjectFromFactoryBean
獲取對象之后,最后返回對象的過程中操作 postProcessObjectFromFactoryBean
做了哪些工作?
AbstractAutowireCapableBeanFactory#postProcessObjectFromFactoryBean
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()) {
result = beanProcessor.postProcessAfterInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
對于后處理器,后面來進行介紹。這里我們只需要了解在 Spring 獲取 bean 的規則中有這樣一條:盡可能保證所有 bean 初始化后都會調用注冊的 BeanPostProcesser 的 postProcessAfterInitialization 方法進行處理,在世紀開發過程中可以根據此特性設計自己的邏輯業務。
獲取單例
之前我們講解了從緩存中獲取單例的過程,那么,如果緩存中不存在已經加載的單例bean就需要從頭開始bean的加載過程了,而Spring中使用getSingleton的重載方法實現bean的加載過程。
AbstractBeanFactory#getBean
片段
// 實例化依賴的 bean 后便可以實例化 mbd 本身了
// singleton 模式的創建
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
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);
}
DefaultSingletonBeanRegistry#getSingleton
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "'beanName' must not be null");
// 全局變量需要同步
synchronized (this.singletonObjects) {
// 首先檢查對應的 bean 是否已經加載過了,因為 singleton 模式其實就是復用以創建的 bean,
// 所以這步是必須的
Object singletonObject = this.singletonObjects.get(beanName); // 1
// 如果為空才可以進行 singleton 的 bean 的初始化
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 + "'"); // 2
}
beforeSingletonCreation(beanName); // 3
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<Exception>();
}
try {
// 初始化 bean
singletonObject = singletonFactory.getObject(); // 4
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); // 5
}
if (newSingleton) {
// 加入緩存
addSingleton(beanName, singletonObject); // 6
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null); // 7
}
}
檢查緩存是否已經加載過了
若沒有加載,則記錄 beanName 的正在加載狀態
-
加載單例前記錄加載狀態,通過
this.singletonsCurrentlyInCreation.add(beanName)
,以便于對循環依賴進行檢測protected void beforeSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } }
通過調用參數傳入的
ObjectFactory
的個體Object
方法實例化bean
-
加載單例后的處理方法調用。當
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"); } }
-
將結果記錄至緩存并刪除加載
bean
過程中所記錄的各種輔助狀態protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT)); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } }
返回處理結果
雖然我們已經從外部了解了加載bean的邏輯架構,但現在我們還并沒有開始對bean加載功能的探索,之前提到過, bean 的加載邏輯其實是在傳入的 ObjectFactory 類型的參數singletonFactory中定義的,我們反推參數的獲取,得到如下代碼:
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
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;
}
}
});
ObjectFactory
的核心部分其實只是調用了 createBean
的方法,所以,繼續~
準備創建 bean
AbstractAutowireCapableBeanFactory#createBean
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("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,根據設置的 class 屬性或者根據 className 來解析 Class
Class<?> resolvedClass = resolveBeanClass(mbd, beanName); // 1
// 如果解析成功則 clone RootBeanDefinition 并且設置其 bean 類為解析之后的 class
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
// 驗證及準備覆蓋的方法
try {
mbdToUse.prepareMethodOverrides(); // 2
}
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.
// 給 BeanPostProcessors 一個機會來返回代理來替代真正的實例
Object bean = resolveBeforeInstantiation(beanName, mbdToUse); // 3
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
Object beanInstance = doCreateBean(beanName, mbdToUse, args); // 4
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
- 根據設置的 class 屬性或者根據 className 來解析 Class
- 對 override 屬性進行標記及驗證(
lookup-method
andreplace-method
) - 應用初始化前的后處理器,解析指定 bean 是否存在初始化前的短路操作
- 創建 bean
處理 override
屬性
public void prepareMethodOverrides() throws BeanDefinitionValidationException {
// Check that lookup methods exists.
MethodOverrides methodOverrides = getMethodOverrides();
if (!methodOverrides.isEmpty()) {
Set<MethodOverride> overrides = methodOverrides.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) {
// Mark override as not overloaded, to avoid the overhead of arg type checking.
// 標記 MethoOverride 暫未被覆蓋,避免參數類型檢查的開銷
mo.setOverloaded(false);
}
}
對于方法的匹配來講,如果一個類中存在若干個重載方法,那么,在函數調用及增強的時候還需要根據參數類型進行匹配,來最終確認當前調用的到底是哪個函數。但是,Spring將一部分匹配工作在這里完成了,如果當前類中的方法只有一個,那么就設置重載該方法沒有被重載,這樣在后續調用的時候便可以直接使用找到的方法,而不需要進行方法的參數匹配驗證了,而且還可以提前對方法存在性進行驗證,正可謂一箭雙雕。
實例化的前置處理
AOP基于前置處理后的短路判斷
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
// 給 BeanPostProcessors 一個機會來返回代理來替代真正的實例
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
// 提供一個短路判斷,當經過處理之后的 bean 若不為空,則直接返回結果。
// 我們所熟知的 AOP 功能就是基于這里的判斷
if (bean != null) {
return bean;
}
}
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
// 如果尚未被解析
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
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
與 applyBeanPostProcessorsAfterInitialization
分別對應實例化前后的處理器,實現也挺簡單的,無非是對后處理器中的所有 InstantiationAwareBeanPostProcessor
類型的后處理器進行 postProcessBeforeInstantiation
方法和 BeanPostProcessor
的 postProcessAfterInitialization
方法的調用
實例化前的后處理器應用
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;
}
實例化后的后處理器應用
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessAfterInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
在講解從緩存中獲取單例bean的時候就提到過,Spring中的規則是在bean的初始化后盡可能保證將注冊的后處理器的postProcessAfterInitialization方法應用到該bean中,因為如果返回的bean不為空,那么便不會再次經歷普通bean的創建過程,所以只能在這里應用后處理器的postProcessAfterInitialization方法。
循環依賴
什么是循環依賴
循環依賴就是循環引用,就是兩個或多個 bean 相互之間持有對方。循環依賴不是循環調用,循環調用是指方法之間的環調用的,循環調用除非有終止條件,否則無法解決。
Spring 如何解決循環依賴
我們先來定義一個循環引用類:
package io.github.binglau.circle;
/**
* 文件描述:
*/
public class TestA {
private TestB testB;
public void a() {
testB.b();
}
public TestB getTestB() {
return testB;
}
public void setTestB(TestB testB) {
this.testB = testB;
}
}
package io.github.binglau.circle;
/**
* 文件描述:
*/
public class TestB {
private TestC testC;
public void b() {
testC.c();
}
public TestC getTestC() {
return testC;
}
public void setTestC(TestC testC) {
this.testC = testC;
}
}
package io.github.binglau.circle;
/**
* 文件描述:
*/
public class TestC {
private TestA testA;
public void c() {
testA.a();
}
public TestA getTestA() {
return testA;
}
public void setTestA(TestA testA) {
this.testA = testA;
}
}
在 Spring 中將循環依賴的處理分成了 3 中情況
構造器循環依賴
無法解決,拋出 BeanCurrentlyInCreationException
異常
Spring容器將每一個正在創建的bean標識符放在一個“當前創建bean池”中,bean標識符在創建過程中將一直保持在這個池中,因此如果在創建 bean 過程中發現自己已經在“當前創建bean池”里時,將拋出BeanCurrentlyInCreationException異常表示循環依賴;而對于創建完畢的bean將從“當前創建bean池”中清除掉。
直觀的測試
-
創建配置文件
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <bean id="testA" class="io.github.binglau.circle.TestA"> <constructor-arg index="0" ref="testB"/> </bean> <bean id="testB" class="io.github.binglau.circle.TestB"> <constructor-arg index="0" ref="testC"/> </bean> <bean id="testC" class="io.github.binglau.circle.TestC"> <constructor-arg index="0" ref="testA"/> </bean> </beans>
-
創建測試用例
@Test(expected = BeanCurrentlyInCreationException.class) public void testCircleByConstructor() throws Throwable { try { new ClassPathXmlApplicationContext("test.xml"); } catch (Exception e) { Throwable el = e.getCause().getCause().getCause(); throw el; } }
setter 循環依賴
表示通過 setter 注入方式構成的循環依賴。對于 setter 注入造成的依賴是通過 Spring 容器提前暴露剛完成構造器注入但未完成其他步驟(如 setter 注入)的 bean 來完成的,而且只能解決單例作用域的 bean 循環依賴。通過提前暴露一個單例工廠方法,從而使其他 bean 能引用到該 bean ,如下代碼所示:
addSingletonFactory(beanName, new ObjectFactory() {
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
具體步驟如下:
- Spring 容器創建單例
testA
bean,首先根據無參構造器創建 bean,并暴露一個ObjectFactory
用于返回一個提前暴露一個創建中的 bean,并將testA
標識符放到 『當前創建 bean 池』,然后進行 setter 注入testB
。 - Spring 容器創建單例
testB
bean,首先根據無參構造器創建 bean,并暴露一個ObjectFactory
用于返回一個提前暴露一個創建中的 bean,并將“testB”標識符放到『當前創建bean池』,然后進行 setter 注入circle
。 - Spring 容器創建單例
testC
bean,首先根據無參構造器創建 bean,并暴露一個ObjectFactory
用于返回一個提前暴露一個創建中的 bean,并將testC
標識符放到『當前創建bean池』,然后進行setter注入testA
。進行注入testA
時由于提前暴露了ObjectFactory
工廠,從而使用它返回提前暴露一個創建中的 bean。 - 最后在依賴注入
testB
和testA
,完成 setter 注入。
prototype 范圍的依賴處理
對于 prototype
作用域 bean,Spring 容器無法完成依賴注入,因為 Spring 容器不進行緩存 prototype
作用域的 bean,因此無法提前暴露一個創建中的 bean。
關于創建 bean 詳見下篇文章