記得跟老婆談戀愛時,有一天心血來潮給老婆作飯,按照菜譜一步一步的作,結果差點把廚房燒了!!!java
上一篇說了,AbstractBeanFactory.getBean的主流程 ,今天來講下其中的createBean方法,程序入口以下:spring
/**.
* 這個類的核心方法,建立一個bean實例, 填充bean實例,執行後處理等
* @see #doCreateBean 詳見doCreateBean
*/
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
//.....
}
複製代碼
根據註釋核心邏輯在doCreateBean 中,下面我們就聊聊doCreateBean.緩存
主流程 | 類比按菜譜作菜 |
---|---|
1. 實例化Bean BeanDefinition->BeanWrapper(若是是單例,先嚐試從緩存中清楚並獲取BeanWrapper) | 找到菜譜,先嚐試從收藏中獲取 |
2.處理MergedBeanDefinitionPostProcessors | 融合老婆的要求,到菜譜中。例如:少放鹽 |
3.容許提早暴露ObjectFactory,解決循環引用問題(必須知足:單例&&容許循環引用&&對應的bean在建立) | 提早告訴老婆菜的大概味道,方便美麗的她準備飲料,也能夠方便本身提早找出盤子 |
4.填充屬性 | 炒菜 |
5.執行 init-method方法 | 試吃 |
6.有其餘bean依賴當前完整bean(必須填充完屬性),移除這些bean,有不能移除的拋出異常 | 發現以前準備的盤子過小了,換個新的。 |
7.註冊DisposableBean接口或destroy—method | 作個好男人,吃完飯記得刷碗 |
源碼註釋在最後!!bash
BeanDerfinition已經上篇已經作過介紹(上一篇blog的傳送門),下面說下BeanWrapper。 org.springframework.beans,BeanWrapper的註釋翻譯以下:app
BeanWrapper是Spring中底層javaBean的核心接口 一般不直接使用,而是被BeanFactory和DataBinder使用 它提供對標準javabean的分析和操做的功能。 能夠獲取,設置屬性值,獲取屬性值的descriptors,用於查詢可讀,可寫的屬性。 支持無限層嵌套屬性。 BeanWrapper默認不支持對屬性的舊值進行編輯,這樣能夠避免getter被調用時產生的反作用 設置 extractOldValueForEditor 爲true,能夠開啓對舊屬性值進行編輯。ide
知道了BeanWrapper就不難猜出BeanDefinition->BeanWrapper的大體邏輯了函數
BeanDefinition->BeanWrapper 就是將bean的元數據,轉換爲Bean,可是Bean沒有對屬性進行賦值。
-- 溫安適 胡亂總結於20190921post
createBeanInstance的源碼:ui
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// 確認 bean的class,在這時已被解析了
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());
}
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// 判斷 是否從新建立同一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() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// 得到首選的構造器,多是默認構造器
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}
// 沒有特別處理簡單實用,無參構造器
return instantiateBean(beanName, mbd);
}
複製代碼
咱們能夠看到,這個createBeanInstance ,有3種處理方式this
通常按照反射生成實例的方式以下方式:
public static void main(String[] args) throws Exception{
Class<CouponApplicationTests> clazz=CouponApplicationTests.class;
clazz.newInstance();
Constructor constructorToUse = clazz.getDeclaredConstructor();
constructorToUse.newInstance()
}
複製代碼
Spring是如何實現的基本相似。查閱instantiateBean的源碼發現,其核心邏輯委託給InstantiationStrategy的instantiate方法。Spring5.X的默認InstantiationStrategy 是CglibSubclassingInstantiationStrategy,而instantiate的實現並不在CglibSubclassingInstantiationStrategy中而是在,其父類SimpleInstantiationStrategy中。以下:
@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides. // 若是沒有override方法, 即沒有使用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); } } } //就是執行constructorToUse.newInstance() return BeanUtils.instantiateClass(constructorToUse); } else { // Must generate CGLIB subclass. return instantiateWithMethodInjection(bd, beanName, owner); } } 複製代碼
若是沒有MethodOverride,其大體邏輯,跟我們寫的差很少。 可是若是有MethodOverride則不一樣。
看到這裏的時候我很好奇hasMethodOverrides和instantiateWithMethodInjection,看名稱我猜想是對@Override註解進行處理,可是看了源碼這個MethodOverrides是指replace-method和lookup-method,這個2配置,我沒有使用過,查詢了源碼與網上的blog。簡單說就是在這裏利用Cglib實現方法注入。 對lookup-method和replace-method的說明您能夠查閱
什麼是循環引用,舉個列子:BeanA引用BeanB,BeanB也引用BeanA
@Component
class BeanA{
@Autowired
BeanB beanB;
}
@Component
class BeanB{
@Autowired
BeanA beanA;
}
複製代碼
Spring只能解決單例類型的循環,其解決幫扶就是提早暴露ObjectFactory,將未填充完屬性的bean提早暴露出來。 流程圖以下:
寫blog比看源碼要費勁的多,我老是嘗試使用生活中的例子比喻主流程,再加一點的補充說明。 以作菜比喻Spring源碼,感受本身源碼學雖然不透徹,可是胃口好多了。
作菜喻源碼
輪廓漸清晰
理解未透徹
肚子叫呱呱
美餐一頓去
下回咱再聊
/**
* 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,此時建立前預處理已經執行了(查看postProcessBeforeInstantiation)。
* 區分默認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 {
// Instantiate the bean.
// 1.實例化bean
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
//Cache of unfinished FactoryBean instances 從FactoryBean name to BeanWrapper.
//移除未完成的bean的緩存中的實例
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//建立Bean實例 將BeanDefinition替換成BeanWrapper
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) {
//Bean
if (!mbd.postProcessed) {
try {
//@AutoWired註解在這裏,應用
//2.處理MergedBeanDefinitionPostProcessors
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.
// 3.容許提早暴露ObjectFactory,解決循環引用問題
// 單例,容許循環引用,對應的bean在建立
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.
// 實例化bean
Object exposedObject = bean;
try {
//4.填充屬性
populateBean(beanName, mbd, instanceWrapper);
//5.執行 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.有其餘bean依賴當前完整bean(填充過屬性),移除這些bean,有不能移除的拋出異常
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
//不容許注入未被徹底裝載的bean,而且有其餘Bean依賴當前這個Bean
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
//移除依賴於當前Bean的其餘bean
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
//還有其餘bean,依賴於當前Bean,未被移除
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 {
//7.若是實現了 DisposableBean接口或者提供了destroy—method 在這裏註冊
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
複製代碼