Spring Ioc原始碼分析系列--Bean例項化過程(二)
前言
上篇文章Spring Ioc原始碼分析系列--Bean例項化過程(一)簡單分析了getBean()
方法,還記得分析了什麼嗎?不記得了才是正常的,記住了才是怪人,忘記了可以回去翻翻,翻不翻都沒事, 反正最後都會忘了。
這篇文章是給上篇填坑的,上篇分析到真正建立Bean的createBean(beanName, mbd, args)
就沒有繼續深入去分析了,繞得太深,說不清楚。那麼這一篇,就續上這個口子,去分析createBean(beanName, mbd, args)
方法。
原始碼分析
話不多說,我們直接來到createBean(beanName, mbd, args)
方法的原始碼。具體的實現是在AbstractAutowireCapableBeanFactory#createBean(beanName, mbd, args)
裡,可以直接定位到這裡。
createBean()方法
跟進程式碼檢視,這個方法也比較簡單,主要分為了以下幾點:
- 初始化化
Class
物件。呼叫resolveBeanClass(mbd, beanName)
方法獲取class
物件,這裡會去解析類全限定名,最終是通過反射方法Class<?> resolvedClass = ClassUtils.forName(className, classLoader)
獲取Class
物件。 - 檢查覆蓋方法。對應的是
mbdToUse.prepareMethodOverrides()
方法,這裡會對一些過載方法進行標記預處理,如果同方法名的方法只存在一個,那麼會將覆蓋標記為未過載,以避免 arg 型別檢查的開銷。 - 應用後置處理器。在例項化物件前,會經過後置處理器處理,這個後置處理器的提供了一個短路機制,就是可以提前結束整個Bean的生命週期,直接從這裡返回一個Bean。
- 建立Bean。呼叫
doCreateBean()
方法進行Bean的建立,在Spring裡面,帶有do開頭的一般是真正幹活的方法,所以Ioc建立Bean到這裡,才是真正要到幹活的地方了。
我們庖丁解牛先把方法不同的功能按照邏輯拆分了,那接下來,就詳細分析一下每個部分。
/**
* Central method of this class: creates a bean instance,
* populates the bean instance, applies post-processors, etc.
*
* 此類的中心方法:建立 bean 例項、填充 bean 例項、應用後處理器等。
*
* @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 ,根據設定的 class 屬性或者根據 className 來解析 Class
// 解析得到beanClass,為什麼需要解析呢?如果是從XML中解析出來的標籤屬性肯定是個字串嘛
// 所以這裡需要載入類,得到Class物件
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.驗證及準備覆蓋的方法
// 對XML標籤中定義的lookUp屬性進行預處理,
// 如果只能根據名字找到一個就標記為非過載的,這樣在後續就不需要去推斷到底是哪個方法了,
// 對於@LookUp註解標註的方法是不需要在這裡處理的,
// AutowiredAnnotationBeanPostProcessor會處理這個註解
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.
//給BeanPostProcessors一個露臉的機會
// 在例項化物件前,會經過後置處理器處理
// 這個後置處理器的提供了一個短路機制,就是可以提前結束整個Bean的生命週期,直接從這裡返回一個Bean
// 不過我們一般不會這麼做,它的另外一個作用就是對AOP提供了支援,
// 在這裡會將一些不需要被代理的Bean進行標記,就本IoC系列文章而言,你可以暫時理解它沒有起到任何作用
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
//若果有自定義bean則直接返回了bean,不會再走後續的doCreateBean方法
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
// 不存在提前初始化的操作,開始正常的建立流程
// doXXX方法,真正幹活的方法,doCreateBean,真正建立Bean的方法
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
// 省略部分異常..
}
}
}
初始化Class物件
很顯然初始化Class
物件的程式碼在resolveBeanClass(mbd, beanName)
方法裡,跟進程式碼檢視。
/**
* Resolve the bean class for the specified bean definition,
* resolving a bean class name into a Class reference (if necessary)
* and storing the resolved Class in the bean definition for further use.
*
* 為指定的 bean 定義解析 bean 類,將 bean 類名稱解析為 Class 引用(如果需要)並將解析的 Class 儲存在 bean 定義中以供進一步使用。
*
* @param mbd the merged bean definition to determine the class for
* @param beanName the name of the bean (for error handling purposes)
* @param typesToMatch the types to match in case of internal type matching purposes
* (also signals that the returned {@code Class} will never be exposed to application code)
* 在內部型別匹配的情況下要匹配的型別(也表示返回的 {@code Class} 永遠不會暴露給應用程式程式碼)
* @return the resolved bean class (or {@code null} if none)
* @throws CannotLoadBeanClassException if we failed to load the class
*/
@Nullable
protected Class<?> resolveBeanClass(final RootBeanDefinition mbd, String beanName, final Class<?>... typesToMatch)
throws CannotLoadBeanClassException {
try {
// 如果已經建立過,直接返回
if (mbd.hasBeanClass()) {
return mbd.getBeanClass();
}
if (System.getSecurityManager() != null) {
return AccessController.doPrivileged((PrivilegedExceptionAction<Class<?>>) () ->
doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());
}
else {
// 否則進行建立
return doResolveBeanClass(mbd, typesToMatch);
}
}
catch (PrivilegedActionException pae) {
// 省略部分異常處理
}
}
跟進doResolveBeanClass(mbd, typesToMatch)
方法,我們這裡傳入的typesToMatch
引數物件陣列為空,所以不會走排除部分類的邏輯,接下來是使用evaluateBeanDefinitionString()
方法計算表示式如果傳入的className
有佔位符,會在這裡被解析,最終正常我們會走到mbd.resolveBeanClass(beanClassLoader)
方法裡。
private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch)
throws ClassNotFoundException {
// 獲取類載入器
ClassLoader beanClassLoader = getBeanClassLoader();
ClassLoader dynamicLoader = beanClassLoader;
boolean freshResolve = false;
if (!ObjectUtils.isEmpty(typesToMatch)) {
// When just doing type checks (i.e. not creating an actual instance yet),
// use the specified temporary class loader (e.g. in a weaving scenario).
// 當只是進行型別檢查(即尚未建立實際例項)時,請使用指定的臨時類載入器(例如在編織場景中)。
ClassLoader tempClassLoader = getTempClassLoader();
if (tempClassLoader != null) {
dynamicLoader = tempClassLoader;
freshResolve = true;
if (tempClassLoader instanceof DecoratingClassLoader) {
DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
for (Class<?> typeToMatch : typesToMatch) {
dcl.excludeClass(typeToMatch.getName());
}
}
}
}
String className = mbd.getBeanClassName();
if (className != null) {
Object evaluated = evaluateBeanDefinitionString(className, mbd);
if (!className.equals(evaluated)) {
// A dynamically resolved expression, supported as of 4.2...
if (evaluated instanceof Class) {
return (Class<?>) evaluated;
}
else if (evaluated instanceof String) {
className = (String) evaluated;
freshResolve = true;
}
else {
throw new IllegalStateException("Invalid class name expression result: " + evaluated);
}
}
if (freshResolve) {
// When resolving against a temporary class loader, exit early in order
// to avoid storing the resolved Class in the bean definition.
// 當針對臨時類載入器解析時,請提前退出以避免將解析的類儲存在 bean 定義中。
if (dynamicLoader != null) {
try {
// 使用臨時動態載入器載入 class 物件
return dynamicLoader.loadClass(className);
}
catch (ClassNotFoundException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Could not load class [" + className + "] from " + dynamicLoader + ": " + ex);
}
}
}
// 反射載入 class 物件
return ClassUtils.forName(className, dynamicLoader);
}
}
// Resolve regularly, caching the result in the BeanDefinition...
// 正常解析,將結果快取在 BeanDefinition...
return mbd.resolveBeanClass(beanClassLoader);
}
跟進mbd.resolveBeanClass(beanClassLoader)
方法,可以看到這裡就是使用反射初始化Class
物件,然後快取在BeanDefinition
中。到這裡,已經完成了從一個字串的類名到一個Class
物件的轉換了,我們已經得到了一個可以使用的Class
物件。
/**
* Determine the class of the wrapped bean, resolving it from a
* specified class name if necessary. Will also reload a specified
* Class from its name when called with the bean class already resolved.
*
* 確定被包裝的 bean 的類,必要時從指定的類名解析它。當使用已解析的 bean 類呼叫時,還將從其名稱中重新載入指定的類。
*
* @param classLoader the ClassLoader to use for resolving a (potential) class name
* @return the resolved bean class
* @throws ClassNotFoundException if the class name could be resolved
*/
@Nullable
public Class<?> resolveBeanClass(@Nullable ClassLoader classLoader) throws ClassNotFoundException {
String className = getBeanClassName();
if (className == null) {
return null;
}
Class<?> resolvedClass = ClassUtils.forName(className, classLoader);
this.beanClass = resolvedClass;
return resolvedClass;
}
檢查覆蓋方法
初始化class物件已經完成了,接下來會去處理過載方法,處理的邏輯在mbdToUse.prepareMethodOverrides()
方法裡。
摘取《Spring原始碼深度解析》裡面的一段話:
很多讀者可能會不知道這個方法的作用,因為在 Spring 的配置裡面根本就沒有諸如
override-method
之類的配置, 那麼這個方法到底是幹什麼用的呢? 其實在 Spring 中確實沒有override-method
這樣的配置,但是在 Spring 配置中是存在lookup-method
和replace-method
的,而這兩個配置的載入其實就是將配置統一存放在BeanDefinition
中的methodOverrides
屬性裡,而這個函式的操作其實也就是針對於這兩個配置的。
lookup-method
通常稱為獲取器注入,spring in action 中對它的描述是,一種特殊的方法注入,它是把一個方法宣告為返回某種型別的 bean,而實際要返回的 bean 是在配置檔案裡面配置的,可用在設計可插拔的功能上,解除程式依賴。 這裡會對一些過載方法進行標記預處理,如果同方法名的方法只存在一個,那麼會將覆蓋標記為未過載,以避免 arg 型別檢查的開銷。
這種騷操作我們基本是不會使用的,所以簡單看一下程式碼,淺嘗輒止,有興趣可以去翻翻。
/**
* Validate and prepare the method overrides defined for this bean.
* Checks for existence of a method with the specified name.
*
* 驗證並準備為此 bean 定義的方法覆蓋。檢查具有指定名稱的方法是否存在。
*
* @throws BeanDefinitionValidationException in case of validation failure
*/
public void prepareMethodOverrides() throws BeanDefinitionValidationException {
// Check that lookup methods exist and determine their overloaded status.
// 檢查查詢方法是否存在並確定它們的過載狀態。
if (hasMethodOverrides()) {
getMethodOverrides().getOverrides().forEach(this::prepareMethodOverride);
}
}
可以看到這裡就獲取所有methodOverrides
,然後遍歷去呼叫prepareMethodOverride()
方法,跟進prepareMethodOverride()
方法。可以看到這裡就是做個簡單的標記。
/**
* Validate and prepare the given method override.
* Checks for existence of a method with the specified name,
* marking it as not overloaded if none found.
*
* 驗證並準備給定的方法覆蓋。檢查具有指定名稱的方法是否存在,如果沒有找到,則將其標記為未過載。
*
* @param mo the MethodOverride object to validate
* @throws BeanDefinitionValidationException in case of validation failure
*/
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.
// 將覆蓋標記為未過載,以避免 arg 型別檢查的開銷。
mo.setOverloaded(false);
}
}
應用後置處理器
在例項化物件前,會經過後置處理器處理,這個後置處理器的提供了一個短路機制,就是可以提前結束整個Bean的生命週期,直接從這裡返回一個Bean。不過我們一般不會這麼做,它的另外一個作用就是對AOP提供了支援,在這裡會將一些不需要被代理的Bean進行標記,就本IoC系列文章而言,你可以暫時理解它沒有起到任何作用。
跟進程式碼resolveBeforeInstantiation(beanName, mbdToUse)
檢視。
/**
* Apply before-instantiation post-processors, resolving whether there is a
* before-instantiation shortcut for the specified bean.
*
* 應用例項化前後處理器,解析指定 bean 是否存在例項化前快捷方式。
* 例項化前的快捷方式的意思這裡可能會直接返回一個定義的代理,而不需要在把目標類初始化
*
* @param beanName the name of the bean
* @param mbd the bean definition for the bean
* @return the shortcut-determined bean instance, or {@code null} if none
*/
//注意單詞Instantiation和Initialization區別
@Nullable
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()) {
// 確定給定的 bean 的型別
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
// 提供一個提前初始化的時機,這裡會直接返回一個例項物件
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
// 如果提前初始化成功,則執行 postProcessAfterInitialization() 方法,注意單詞Instantiation和Initialization區別
// 關於這一塊的邏輯,細心的一點的會發現,這裡漏了例項化後置處理、初始化前置處理這兩個方法。
// 而是在提前返回物件後,直接執行了初始化後置處理器就完成了bean的整個流程,
// 相當於是提供了一個短路的操作,不再經過Spring提供的繁雜的各種處理
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
// 設定是否已經提前例項化
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
跟進applyBeanPostProcessorsBeforeInstantiation()
程式碼檢視。這裡只要有一個 InstantiationAwareBeanPostProcessor
返回的結果不為空,則直接返回,說明多個 InstantiationAwareBeanPostProcessor
只會生效靠前的一個,注意單詞Instantiation和Initialization區別。
/**
* spring bean 初始化流程
* Bean 初始化(Initialization)
* 1.@PoseConstruct 方法
* 2.實現InitializingBean 介面的afterPropertiesSet()方法
* 3.自定義初始化方法
*/
@Nullable
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);
// 如果為空,表示不作任何調整
// 這裡只要有一個 InstantiationAwareBeanPostProcessor 返回的結果不為空,則直接返回,
// 說明多個 InstantiationAwareBeanPostProcessor 只會生效靠前的一個
if (result != null) {
return result;
}
}
}
return null;
}
跟進applyBeanPostProcessorsAfterInitialization()
方法,邏輯跟上面的是類似的,注意單詞Instantiation和Initialization區別。
@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;
}
建立Bean
經過上面的步驟,有驚無險,我們來到了doCreateBean(beanName, mbdToUse, args)
方法,這是真正進行Bean建立的地方,所以這裡才是真的進入正文,前面都是打醬油走走過程。
當經歷過 resolveBeforelnstantiation()
方法後,程式有兩個選擇 ,如果建立了代理或者說重寫了 InstantiationAwareBeanPostProcessor
的 postProcessBeforelnstantiation()
方法並在方法 postProcessBeforelnstantiation()
中改變了 bean
, 則直接返回就可以了 , 否則需要進行常規 bean
的建立。 而這常規 bean 的建立就是在 doCreateBean()
中完成的。
直接跟進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.
*
* 實際建立指定的bean。
* 此時已經進行了預建立處理,例如檢查 {@code postProcessBeforeInstantiation} 回撥。
* <p>區分預設 bean 例項化、使用工廠方法和自動裝配建構函式。
*
* @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 {
// 這個方法真正建立了Bean,建立一個Bean會經過 建立物件 > 依賴注入 > 初始化
// 這三個過程,在這個過程中,BeanPostProcessor會穿插執行,
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//根據指定bean使用對應的策略建立新的例項,如工廠方法,建構函式自動注入,簡單初始化
// 這裡真正的建立了物件
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.
// 按照官方的註釋來說,這個地方是Spring提供的一個擴充套件點,
// 對程式設計師而言,我們可以通過一個實現了MergedBeanDefinitionPostProcessor的後置處理器
// 來修改bd中的屬性,從而影響到後續的Bean的生命週期
// 不過官方自己實現的後置處理器並沒有去修改bd,
// 而是呼叫了applyMergedBeanDefinitionPostProcessors方法
// 這個方法名直譯過來就是-應用合併後的bd,也就是說它這裡只是對bd做了進一步的使用而沒有真正的修改
synchronized (mbd.postProcessingLock) {
// bd只允許被處理一次
if (!mbd.postProcessed) {
try {
// 應用合併後的bd
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
// 標註這個bd已經被MergedBeanDefinitionPostProcessor的後置處理器處理過
// 那麼在第二次建立Bean的時候,不會再次呼叫applyMergedBeanDefinitionPostProcessors
mbd.postProcessed = true;
}
}
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
//是否需要提前暴露mbd.isSingleton() && this.allowCircularReferences &&
// isSingletonCurrentlyInCreation(beanName)
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");
}
//為避免後期迴圈依賴,可以在bean初始化完成前將建立例項的ObjectFactory加入工廠
//getEarlyBeanReference對bean再一次依賴引用,主要應用SmartInstantiationAwareBeanPostProcessor
//其中我們熟悉的AOP就是在這裡將advice動態織入bean中,若沒有則直接返回bean,不做任何處理
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
// 初始化例項
Object exposedObject = bean;
try {
//對bean進行填充,對各個屬性進行注入,可能存在依賴其他bean的屬性,則會遞迴初始化依賴bean
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);
//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還沒有被完全建立好
* 也就是說還存在迴圈依賴
*/
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 {
//根據scope註冊bean
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
分析一下這個函式設計思路:
- 如果是單例則需要首先清除快取。
- 例項化 bean ,將 BeanDefinition 轉換為 BeanWrapper。 轉換是一個複雜的過程,但是我們可以嘗試概括大致的功能,如下所示。
- 如果存在工廠方法則使用工廠方法進行例項化。
- 如果一個類有多個建構函式,每個建構函式都有不同的引數,所以需要根據引數鎖定構造 函式並進行例項化。
- 如果既不存在工廠方法也不存在帶有引數的建構函式,則使用預設的建構函式進行 bean 的例項化。
MergedBeanDefinitionPostProcessor
的應用。 bean 合併後的處理,Autowired
註解正是通過此方法實現諸如型別的預解析。- 依賴處理。 在 Spring 中會有迴圈依賴的情況,例如,當 A 中含有 B 的屬性,而 B 中又含有 A 的屬性 時就會構成一個迴圈依賴,此時如果 A 和 B 都是單例,那麼在 Spring 中的處理方式就是當建立 B 的時候,涉及自動注入 A 的步驟,並不是直接去再次建立 A,而是通過放入快取中的
ObjectFactory
來建立例項,這樣就解決了迴圈依賴的問題。 - 屬性填充。 將所有屬性填充至 bean 的例項中。
- 呼叫初始化方法。在屬性填充完成後,這裡會進行初始化方法的呼叫。
- 迴圈依賴檢查。 之前有提到過,在 Sping 中解決迴圈依賴只對單例有效,而對於
prototype
的 bean, Spring 沒有好的解決辦法,唯一要做的就是丟擲異常。 在這個步驟裡面會檢測已經載入的 bean 是否 已經出現了依賴迴圈,並判斷是再需要丟擲異常。 - 註冊
DisposableBean
。 如果配置了destroy-method
,這裡需要註冊以便於在銷燬時候呼叫。 - 完成建立井返回。
可以看到上面的步驟非常的繁瑣,每一步驟都使用了大量的程式碼來完成其功能,最複雜也是最難以理解的當屬迴圈依賴的處理,在真正進入 doCreateBean()
前我們有必要先了解下迴圈依賴,這裡會在下一篇文章Spring Ioc原始碼分析系列--自動注入迴圈依賴的處理圖文並茂去分析。
下面就按照上述的點逐個分析,接下來肯定是枯燥無味的,那開始吧。
清除factoryBeanInstanceCache快取
首先如果是單例,會到factoryBeanInstanceCache
中獲取是否存在快取,如果有這裡就會從快取裡獲取一個instanceWrapper
,不需要再去走複雜的建立流程了。
對應程式碼如下:
if (mbd.isSingleton()) {
// 你可以暫時理解為,這個地方返回的就是個null
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
例項化 bean
又到了例項化bean,是不是反反覆覆看了很多次,到底哪裡才真的建立一個bean,別慌,這裡真的是真正建立bean的地方了,再套娃就是狗。
跟進createBeanInstance(beanName, mbd, args)
方法。這個方法幹了哪幾件事?
- 首先嚐試呼叫
obtainFromSupplier()
例項化bean - 嘗試呼叫
instantiateUsingFactoryMethod()
例項化bean - 根據給定引數推斷建構函式例項化bean
- 以上均無,則使用預設建構函式例項化bean
/**
* Create a new instance for the specified bean, using an appropriate instantiation strategy:
* factory method, constructor autowiring, or simple instantiation.
*
* 使用適當的例項化策略為指定的 bean 建立一個新例項:工廠方法、建構函式自動裝配或簡單例項化。
*
* @param beanName the name of the bean
* @param mbd the bean definition for the bean
* @param args explicit arguments to use for constructor or factory method invocation
* @return a BeanWrapper for the new instance
* @see #obtainFromSupplier
* @see #instantiateUsingFactoryMethod
* @see #autowireConstructor
* @see #instantiateBean
*/
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
// 確保此時實際解析了 bean 類。
Class<?> beanClass = resolveBeanClass(mbd, beanName);
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());
}
// 通過bd中提供的instanceSupplier來獲取一個物件
// 正常bd中都不會有這個instanceSupplier屬性,這裡也是Spring提供的一個擴充套件點,但實際上不常用
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
//如果工廠方法不為null,則使用工廠方法初始化策略
// bd中提供了factoryMethodName屬性,那麼要使用工廠方法的方式來建立物件,
// 工廠方法又會區分靜態工廠方法跟例項工廠方法
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean...
// 在原型模式下,如果已經建立過一次這個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);
}
}
// Candidate constructors for autowiring?
//需要根據引數解析建構函式
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
//建構函式自動注入
return autowireConstructor(beanName, mbd, ctors, args);
}
// Preferred constructors for default construction?
// 預設構造的首選建構函式?
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}
// No special handling: simply use no-arg constructor.
//使用預設建構函式
return instantiateBean(beanName, mbd);
}
接下來分析以上幾點,算了不分析,太長了。我在另一篇文章Spring Ioc原始碼分析系列--例項化Bean的幾種方法會填坑。這裡會詳細分析上面的幾點,好好把握,估計看到這都不知道啥跟啥了。
MergedBeanDefinitionPostProcessor的應用
到這裡我們已經例項化了一個bean物件,但是這個bean只是個半成品,空有外殼而無內在,所以接下來的工作就是對裡面的內容進行填充。那毫無疑問,按照Spring的尿性,肯定會在真正開始之前給你一個擴充套件點,讓你還要機會在屬性填充之前修改某些東西。我們經常使用的@Autowired
註解就是在這裡實現的,後續會寫一篇Spring Ioc原始碼分析系列--@Autowired註解的實現原理結合原始碼和例子去分析它的實現。
跟進程式碼檢視,比較簡單,就是獲取所有的MergedBeanDefinitionPostProcessor
,然後依次執行它的postProcessMergedBeanDefinition()
方法。
/**
* Apply MergedBeanDefinitionPostProcessors to the specified bean definition,
* invoking their {@code postProcessMergedBeanDefinition} methods.
*
* 將 MergedBeanDefinitionPostProcessors 應用於指定的 bean 定義,
* 呼叫它們的 {@code postProcessMergedBeanDefinition} 方法。
*
* 可以看到這個方法的程式碼還是很簡單的,
* 就是呼叫了MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition方法
*
* @param mbd the merged bean definition for the bean
* @param beanType the actual type of the managed bean instance
* @param beanName the name of the bean
* @see MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition
*/
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof MergedBeanDefinitionPostProcessor) {
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
}
}
}
依賴處理
這部分主要是為了處理迴圈依賴而做的準備,這裡會根據earlySingletonExposure
引數去判斷是否允許迴圈依賴,如果允許,則會呼叫addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean))
方法將bean的早期引用放入到singletonFactories
中。關於迴圈依賴的詳細處理過程,可以在下一篇文章Spring Ioc原始碼分析系列--自動注入迴圈依賴的處理裡看到。
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
//是否需要提前暴露mbd.isSingleton() && this.allowCircularReferences &&
// isSingletonCurrentlyInCreation(beanName)
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");
}
//為避免後期迴圈依賴,可以在bean初始化完成前將建立例項的ObjectFactory加入工廠
//getEarlyBeanReference對bean再一次依賴引用,主要應用SmartInstantiationAwareBeanPostProcessor
//其中我們熟悉的AOP就是在這裡將advice動態織入bean中,若沒有則直接返回bean,不做任何處理
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
跟進addSingletonFactory()
方法,可以看到這裡會先把早期引用放入到singletonFactories
三級快取中。
/**
* Add the given singleton factory for building the specified singleton
* if necessary.
*
* 如有必要,新增給定的單例工廠以構建指定的單例。
*
* <p>To be called for eager registration of singletons, e.g. to be able to
* resolve circular references.
*
* 被提前註冊的單例Bean呼叫,例如用來解決迴圈依賴
*
* @param beanName the name of the bean
* @param singletonFactory the factory for the singleton object
*/
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
那放入到singletonFactories
裡面的是什麼呢?從上面可以看到,這是一個lambada表示式,呼叫的方法的是getEarlyBeanReference()
,跟進程式碼檢視。
/**
* Obtain a reference for early access to the specified bean,
* typically for the purpose of resolving a circular reference.
*
* 獲取對指定 bean 的早期訪問的引用,通常用於解析迴圈引用。
*
* @param beanName the name of the bean (for error handling purposes)
* @param mbd the merged bean definition for the bean
* @param bean the raw bean instance
* @return the object to expose as bean reference
*/
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
// 對 bean 再一次依賴引用
// 主要應用 SmartInstantiationAwareBeanPostProcessor,
// 其中我們熟知的 AOP 就是在這裡將 advice 動態織入 bean 中, 若沒有則直接返回 bean ,不做任何處理
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
屬性填充
到這裡會已經完成了bean的例項化,早期引用的暴露,那接下來就到了屬性填充的部分,開始對bean進行各種賦值,讓一個空殼半成品bean完善成一個有血有肉的正常bean。
這裡可能存在依賴其他bean的屬性,則會遞迴初始化依賴bean。
在 populateBean()
函式中提供了這樣的處理流程。
InstantiationAwareBeanPostProcessor
處理器的postProcessAfterinstantiation
函式的應用, 此函式可以控制程式是否繼續進行屬性填充。- 根據注入型別( byName/byType ),提取依賴的 bean,並統一存入
PropertyValues
中。 - 應用
InstantiationAwareBeanPostProcessor
處理器的postProcessPropertyValues
方法, 對屬性獲取完畢填充前對屬性的再次處理,典型應用是RequiredAnnotationBeanPostProcessor
類中對屬性的驗證。 - 將所有
PropertyValues
中的屬性填充至BeanWrapper
中。
跟進程式碼檢視,又很長,這一塊的程式碼真的是又臭又長。但是註釋很詳細,可以跟著看看。
/**
* Populate the bean instance in the given BeanWrapper with the property values
* from the bean definition.
*
* 使用 bean 定義中的屬性值填充給定 BeanWrapper 中的 bean 例項。
*
* @param beanName the name of the bean
* @param mbd the bean definition for the bean
* @param bw the BeanWrapper with bean instance
*/
@SuppressWarnings("deprecation") // for postProcessPropertyValues
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
//沒有可填充的屬性
return;
}
}
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
boolean continueWithPropertyPopulation = true;
//給InstantiationAwareBeanPostProcessors最後一次機會在屬性設定前來改變 bean
//如:可以用來支援屬性注入的型別
// 滿足兩個條件,不是合成類 && 存在InstantiationAwareBeanPostProcessor
// 其中InstantiationAwareBeanPostProcessor主要作用就是作為Bean的例項化前後的鉤子
// 外加完成屬性注入,對於三個方法就是
// postProcessBeforeInstantiation 建立物件前呼叫
// postProcessAfterInstantiation 物件建立完成,@AutoWired註解解析後呼叫
// postProcessPropertyValues(已過期,被postProcessProperties替代) 進行屬性注入
// 下面這段程式碼的主要作用就是我們可以提供一個InstantiationAwareBeanPostProcessor
// 提供的這個後置處理如果實現了postProcessAfterInstantiation方法並且返回false
// 那麼可以跳過Spring預設的屬性注入,但是這也意味著我們要自己去實現屬性注入的邏輯
// 所以一般情況下,我們也不會這麼去擴充套件
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
//返回值為是否繼續填充bean
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
//如果後處理器發出停止填充命令則終止後續操作
if (!continueWithPropertyPopulation) {
return;
}
// 這裡其實就是判斷XML是否提供了屬性相關配置
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 確認注入模型
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
// 主要處理byName跟byType兩種注入模型,byConstructor這種注入模型在建立物件的時候已經處理過了
// 這裡都是對自動注入進行處理,byName跟byType兩種注入模型均是依賴setter方法
// byName,根據setter方法的名字來查詢對應的依賴,例如setA,那麼就是去容器中查詢名字為a的Bean
// byType,根據setter方法的引數型別來查詢對應的依賴,例如setXx(A a),就是去容器中查詢型別為A的bean
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
//根據名稱注入
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
//根據型別注入
autowireByType(beanName, mbd, bw, newPvs);
}
// pvs是XML定義的屬性
// 自動注入後,bean實際用到的屬性就應該要替換成自動注入後的屬性
pvs = newPvs;
}
//後置處理器已經初始化
// 檢查是否有InstantiationAwareBeanPostProcessor
// 前面說過了,這個後置處理器就是來完成屬性注入的
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
//需要依賴檢查
// 是否需要依賴檢查,預設是不會進行依賴檢查的
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
// 下面這段程式碼有點麻煩了,因為涉及到版本問題
// 其核心程式碼就是呼叫了postProcessProperties完成了屬性注入
PropertyDescriptor[] filteredPds = null;
// 存在InstantiationAwareBeanPostProcessor,我們需要呼叫這類後置處理器的方法進行注入
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 這句就是核心
// Autowired 是通過 AutowiredAnnotationBeanPostProcessor#postProcessProperties() 實現的
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
// 得到需要進行依賴檢查的屬性的集合
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
//對所有需要依賴檢查的屬性做後置處理
// 這個方法已經過時了,放到這裡就是為了相容老版本
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
// 需要進行依賴檢查
if (needsDepCheck) {
if (filteredPds == null) {
// 得到需要進行依賴檢查的屬性的集合
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
//依賴檢查,對應depends-on屬性,3.0已經棄用此屬性
// 對需要進行依賴檢查的屬性進行依賴檢查
checkDependencies(beanName, mbd, filteredPds, pvs);
}
// 將XML中的配置屬性應用到Bean上
if (pvs != null) {
//將屬性應用到bean中
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
這裡看到這裡會根據byName
或者byType
方式尋找依賴,然後呼叫applyPropertyValues()
將屬性注入到BeanWrapperImpl
裡。
先來看autowireByName()
方法,顧名思義,這裡會根據屬性名去獲取依賴。
/**
* Fill in any missing property values with references to
* other beans in this factory if autowire is set to "byName".
*
* 如果 autowire 設定為“byName”,則使用對該工廠中其他 bean 的引用填充任何缺少的屬性值。
*
* @param beanName the name of the bean we're wiring up.
* Useful for debugging messages; not used functionally.
* @param mbd bean definition to update through autowiring
* @param bw the BeanWrapper from which we can obtain information about the bean
* @param pvs the PropertyValues to register wired objects with
*/
protected void autowireByName(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
//尋找bw中需要依賴注入的屬性值
// 得到符合下面條件的屬性名稱
// 1.有setter方法
// 2.需要進行依賴檢查
// 3.不包含在XML配置中
// 4.不是簡單型別(基本資料型別,列舉,日期等)
// 這裡可以看到XML配置優先順序高於自動注入的優先順序
// 不進行依賴檢查的屬性,也不會進行屬性注入
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
if (containsBean(propertyName)) {
//遞迴初始化相關bean
Object bean = getBean(propertyName);
// 將自動注入的屬性新增到pvs中去
pvs.add(propertyName, bean);
//註冊依賴
registerDependentBean(propertyName, beanName);
if (logger.isTraceEnabled()) {
logger.trace("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");
}
}
}
}
接下來看autowireByType()
,該方法會根據屬性的型別去獲取依賴。也比較簡單明瞭。
/**
* Abstract method defining "autowire by type" (bean properties by type) behavior.
* <p>This is like PicoContainer default, in which there must be exactly one bean
* of the property type in the bean factory. This makes bean factories simple to
* configure for small namespaces, but doesn't work as well as standard Spring
* behavior for bigger applications.
*
* 定義“按型別自動裝配”(按型別的 bean 屬性)行為的抽象方法。
* <p>這類似於 PicoContainer 預設值,其中 bean 工廠中必須只有一個屬性型別的 bean。
* 這使得 bean 工廠易於為小型名稱空間配置,但不能像標準 Spring 行為那樣為大型應用程式工作。
*
* @param beanName the name of the bean to autowire by type
* @param mbd the merged bean definition to update through autowiring
* @param bw the BeanWrapper from which we can obtain information about the bean
* @param pvs the PropertyValues to register wired objects with
*/
protected void autowireByType(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
// 這個型別轉換器,主要是在處理@Value時需要使用
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
//尋找bw中需要依賴注入的屬性
// 得到符合下面條件的屬性名稱
// 1.有setter方法
// 2.需要進行依賴檢查
// 3.不包含在XML配置中
// 4.不是簡單型別(基本資料型別,列舉,日期等)
// 這裡可以看到XML配置優先順序高於自動注入的優先順序
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
try {
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
// Don't try autowiring by type for type Object: never makes sense,
// even if it technically is a unsatisfied, non-simple property.
// 不要嘗試為 Object 型別按型別自動裝配:永遠沒有意義,即使它在技術上是一個不令人滿意的、不簡單的屬性。
if (Object.class != pd.getPropertyType()) {
//探測指定屬性的set方法
// 這裡獲取到的就是setter方法的引數,因為我們需要按照型別進行注入嘛
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
// Do not allow eager init for type matching in case of a prioritized post-processor.
// 如果是PriorityOrdered在進行型別匹配時不會去匹配factoryBean
// 如果不是PriorityOrdered,那麼在查詢對應型別的依賴的時候會會去匹factoryBean
// 這就是Spring的一種設計理念,實現了PriorityOrdered介面的Bean被認為是一種
// 最高優先順序的 Bean,這一類的Bean在進行為了完成裝配而去檢查型別時,
// 不去檢查 factoryBean
// 具體可以參考PriorityOrdered介面上的註釋文件
boolean eager = !PriorityOrdered.class.isInstance(bw.getWrappedInstance());
// 將引數封裝成為一個依賴描述符
// 依賴描述符會通過:依賴所在的類,欄位名/方法名,依賴的具體型別等來描述這個依賴
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
/**
* 解析指定beanName的屬性所匹配的值,並把解析到的屬性名儲存在autowiredBeanNames中,
* 當屬性存在多個封裝bean時,如:
* @Autowire
* private List<A> list;
* 將會找到所有匹配A型別的bean並將其注入
* 解析依賴,這裡會處理@Value註解
* 另外,通過指定的型別到容器中查詢對應的bean
*/
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
if (autowiredArgument != null) {
// 將查詢出來的依賴屬性新增到pvs中,後面會將這個pvs應用到bean上
pvs.add(propertyName, autowiredArgument);
}
// 註冊bean直接的依賴關係
for (String autowiredBeanName : autowiredBeanNames) {
//註冊依賴
registerDependentBean(autowiredBeanName, beanName);
if (logger.isTraceEnabled()) {
logger.trace("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);
}
}
}
屬性依賴都獲取完了,接下來就是按部就班的進行注入了。
跟進applyPropertyValues()
方法,邏輯比較複雜。但是最終是呼叫了反射,給對應的屬性進行了賦值,這裡深入的就不再展開了。
/**
* Apply the given property values, resolving any runtime references
* to other beans in this bean factory. Must use deep copy, so we
* don't permanently modify this property.
*
* 應用給定的屬性值,解析對此 bean 工廠中其他 bean 的任何執行時引用。必須使用深拷貝,所以我們不會永久修改這個屬性。
*
* @param beanName the bean name passed for better exception information
* @param mbd the merged bean definition
* @param bw the BeanWrapper wrapping the target object
* @param pvs the new property values
*/
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;
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 {
original = Arrays.asList(pvs.getPropertyValues());
}
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
// Create a deep copy, resolving any references for values.
// 建立一個深拷貝副本,解析任何值的引用。
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();
if (originalValue == AutowiredPropertyMarker.INSTANCE) {
Method writeMethod = bw.getPropertyDescriptor(propertyName).getWriteMethod();
if (writeMethod == null) {
throw new IllegalArgumentException("Autowire marker for property without write method: " + pv);
}
originalValue = new DependencyDescriptor(new MethodParameter(writeMethod, 0), true);
}
// 給定一個 PropertyValue,返回一個值,必要時解析對工廠中其他 bean 的任何引用
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.
// 可能將轉換後的值儲存在合併的 bean 定義中,以避免對每個建立的 bean 例項進行重新轉換。
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);
}
}
呼叫初始化方法
初始化方法的呼叫邏輯在initializeBean(beanName, exposedObject, mbd)
裡面,跟進程式碼檢視。
一看是不是很清晰,所以以後再遇到問你啥啥啥方法先執行,直接叼面試官。
/**
*
* initializeBean()方法依次呼叫四個方法
* 1.invokeAwareMethods()
* 2.applyBeanPostProcessorsBeforeInitialization()
* 3.invokeInitMethods()
* 4.applyBeanPostProcessorsAfterInitialization()
*
*/
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 {
// 1.先呼叫實現 aware 介面的方法
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 2.呼叫 BeanPostProcessor#postProcessBeforeInitialization()方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 3.呼叫初始化方法,例如實現了 InitializingBean#afterPropertiesSet() 方法
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()) {
// 4.最後呼叫 BeanPostProcessor#postProcessAfterInitialization()
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
迴圈依賴檢查
這一步主要是實現一個兜底的檢測,避免出現注入了一個本該被代理的但是卻注入了一個原生bean的情況,這部分會在迴圈依賴的文章裡結合來分析。
先看下程式碼。
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還沒有被完全建立好
* 也就是說還存在迴圈依賴
*/
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.");
}
}
}
}
註冊 DisposableBean
這也是一個回撥的操作,註冊一些銷燬的方法。Spring 中不但提供了對於初始化方法的擴充套件人口 , 同樣也提供了銷燬方法的擴充套件入口,對 於銷燬方法的擴充套件,除了我們熟知的配置屬性 destroy-method
方法外,使用者還可以註冊後處理器 DestructionAwareBeanPostProcessor
來統一處理 bean 的銷燬方法,跟進程式碼registerDisposableBeanIfNecessary()
。
/**
* Add the given bean to the list of disposable beans in this factory,
* registering its DisposableBean interface and/or the given destroy method
* to be called on factory shutdown (if applicable). Only applies to singletons.
*
* 將給定的 bean 新增到該工廠的一次性 bean 列表中,
* 註冊其 DisposableBean 介面和或在工廠關閉時呼叫的給定銷燬方法(如果適用)。僅適用於單例。
*
* @param beanName the name of the bean
* @param bean the bean instance
* @param mbd the bean definition for the bean
* @see RootBeanDefinition#isSingleton
* @see RootBeanDefinition#getDependsOn
* @see #registerDisposableBean
* @see #registerDependentBean
*/
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()) {
// Register a DisposableBean implementation that performs all destruction
// work for the given bean: DestructionAwareBeanPostProcessors,
// DisposableBean interface, custom destroy method.
// 註冊一個為給定 bean 執行所有銷燬工作的 DisposableBean 實現:DestructionAwareBeanPostProcessors、DisposableBean 介面、自定義銷燬方法。
/**
* 單例模式下需要銷燬的bean,此方法中會處理實現DisposableBean的bean
* 並且對所有的bean使用DestructionAwareBeanPostProcessors處理
* DisposableBean DestructionAwareBeanPostProcessors
*/
registerDisposableBean(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
else {
// A bean with a custom scope...
// 自定義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));
}
}
}
總結
本文主要分析了doCreateBean()
方法,但是講得比較粗糙。回憶一下本文的思路,首先是通過類名反射得到一個class
物件,然後推斷建構函式去例項化得到一個bean物件,當然這部分沒有深入細節去說,分多了一篇文章。然後通過byName
和byType
兩種方式去獲取依賴注入,之後通過反射將屬性注入到物件中。除去一些邊邊角角的校驗,總的思路就是這樣,還是相對清晰的,就是細節比較多。
這裡牽扯的東西比較多,也算是Ioc裡面比較難啃的部分了。我回看一遍我寫的文章,覺得整體言不達意,腦子裡想十分,說出來可能只有六分,寫出來的就剩三分了。
個人水平有限,如有錯誤,還請指出。
如果有人看到這裡,那在這裡老話重提。與君共勉,路漫漫其修遠兮,吾將上下而求索。