目錄
下面為非第一次getBean(已經初始化過一次),擷取的最短路徑
1、擷取真實的BeanName(傳入的可能是别名等)
1)、判斷是否為擷取FactoryBean
2)、 判斷是否為别名
2、從緩存中擷取執行個體(如果已經調用過getBean)
3、判斷傳回真正擷取的對象
1、如果源名稱以&開頭,則判斷是否為NullBean,判斷是否不存在(直接抛異常),傳回工廠本身
2、擷取正常的Bean(非FactoryBean類型),則直接傳回。
3、不是擷取FactoryBean本身,但是擷取的是FactoryBean類型的Bean
3-1)、從緩存中擷取(非第一次)
3-2)、擷取執行個體(第一次擷取)
之是以先寫了ApplicationContext的refresh方法再寫繼續寫BeanFactory的getBean核心方法,是因為覺得項目中根本不會直接使用BeanFactory肯定還是會使用ApplicationContext。并且每個Bean的生命周期會在getBean中完成,其中就會回調所有的BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法。
先梳理一下getBean的整個過程(隻分析單利Bean)
1、首先會從緩存中擷取;否則(第一次)需要根據之前注入的BeanDefinition進行建立。
2、建立之前需要先處理ovverride和前置準備;在建立時會有依賴注入的情況(需要解決循環依賴的問題),則再分析真正的建立
3、建立過程:建立Bean執行個體;記錄建立Bean的工廠;屬性注入;初始化Bean(Bean的生命周期在這裡完成,包括注冊DisposableBean)
下面為非第一次getBean(已經初始化過一次),擷取的最短路徑
開始:
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
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);
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
// 省略
}
1、擷取真實的BeanName(傳入的可能是别名等)
調用getBean方法時候,傳入的字元串可能是别名,或者是FactoryBean類型則可能傳入&開頭的,以擷取FactoryBean本身。是以需要考慮各種情況,拿到真是的bean名稱。
protected String transformedBeanName(String name) {
return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
1)、判斷是否為擷取FactoryBean
public static String transformedBeanName(String name) {
if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
return name;
}
return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
do {
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
return beanName;
});
}
判斷名稱是否以&開頭,不是則直接傳回目前字元串;是則是擷取FactoryBean本身,則需要截取字元串,緩存擷取FactoryBean的名稱。緩存到BeanFactoryUtils的
Map<String, String> transformedBeanNameCache
2)、 判斷是否為别名
public String canonicalName(String name) {
String canonicalName = name;
String resolvedName;
do {
resolvedName = this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
}
while (resolvedName != null);
return canonicalName;
}
目前字元串要不是Bean名稱本身,要不是就是别名。那麼直接在别名中擷取一下,有則傳回别名,否則傳回Bean名稱本身。
2、從緩存中擷取執行個體(如果已經調用過getBean)
@Override
@Nullable
public Object getSingleton(String beanName) {
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) {
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;
}
如果第一次調用getBean初始化完成後,則會将執行個體化的Bean放入DefaultSingletonBeanRegistry的singletonObjects容器中;為了解決單利循環依賴的問題,則在依賴注入時,會提前将未完成的Bean提前放入earlySingletonObjects容器中。建立Bean的工廠與Bean名稱的關系存儲在singletonFactories容器中。
- 先直接先看是否初始化完成,如果沒有拿到,則判斷是否正在建立中。
- 如果是則從earlySingletonObjects中進行擷取。并且目前allowEarlyReference參數為true,則如果正在依賴注入建立中,直接從工廠中擷取
- 如果工廠已經存在,則直接getBean調用工廠的getBean方法,并且提前暴露放到earlySingletonObjects中。
3、判斷傳回真正擷取的對象
if (sharedInstance != null && args == null) {
// 省略日志
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
上面擷取到的可能就是需要傳回的Bean,但是目前可能需要擷取的是FactoryBean本身(是否或者FactoryBean已經緩存到BeanFactoryUtils的transformedBeanNameCache中)。擷取時傳入了上面擷取的執行個體,源名稱,Bean名稱,RootBeanDefinition為null。
@Override
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
String currentlyCreatedBean = this.currentlyCreatedBean.get();
if (currentlyCreatedBean != null) {
registerDependentBean(beanName, currentlyCreatedBean);
}
return super.getObjectForBeanInstance(beanInstance, name, beanName, mbd);
}
判斷目前是否正在有依賴注入的Bean沒有初始化完成(非第一次調用則肯定已經初始化完成了),在繼續調用父類AbstractBeanFactory的方法。
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
if (mbd != null) {
mbd.isFactoryBean = true;
}
return beanInstance;
}
// 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.
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
1、如果源名稱以&開頭,則判斷是否為NullBean,判斷是否不存在(直接抛異常),傳回工廠本身
2、擷取正常的Bean(非FactoryBean類型),則直接傳回。
3、不是擷取FactoryBean本身,但是擷取的是FactoryBean類型的Bean
3-1)、從緩存中擷取(非第一次)
getCachedObjectForFactoryBean(beanName);
則在AbstractBeanFactory的父類FactoryBeanRegistrySupport,的factoryBeanObjectCache容器中擷取
@Nullable
protected Object getCachedObjectForFactoryBean(String beanName) {
return this.factoryBeanObjectCache.get(beanName);
}
3-2)、擷取執行個體(第一次擷取)
那麼上面擷取到的beanInstance為FactoryBean,先或者合并的BeanDefinition,再判斷是否為synthetic(合成的)。
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) {
// 直接用FactoryBean中調用getObject方法擷取,或者判斷是否正在建立中
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 (shouldPostProcess) {
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
return object;
}
beforeSingletonCreation(beanName);
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
afterSingletonCreation(beanName);
}
}
if (containsSingleton(beanName)) {
// 放入緩存中,第二次就從緩存中擷取
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
// 省略非單利
}
先用synchronized鎖住singletonObjects,又從緩存中擷取一遍。
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 {
object = factory.getObject();
}
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null) {
if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
object = new NullBean();
}
return object;
}
否則直接從FactoryBean中擷取,但是可能或者不到,則判斷是否正在建立中,則後面從建立中擷取。主要的方法就是FactoryBean#getObject方法。第一次擷取,則也會執行FactoryBean類型的Bean的生命周期的 回調BeanPostProcess的方法。比如之前修改jpa的JpaRepository子類(通過JpaRepositoryFactoryBean#getObject建立)就有該回調。如下:
@Override
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
return applyBeanPostProcessorsAfterInitialization(object, beanName);
}
但是隻回調了所有BeanPostProcessor的postProcessAfterInitialization方法:
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
最後将FactoryBean通過getObject方法,擷取到的對象放入factoryBeanObjectCache緩存,第二次就可以從該容器中擷取了