javascript
Spring Ioc 之 Bean的加载(3):createBean()
createBean()是創建Bean的關鍵方法
一、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;// 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.//判斷需要創建的Bean是否可以實例化,即是否可以通過當前的類加載器加載Class<?> resolvedClass = resolveBeanClass(mbd, beanName);if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {mbdToUse = new RootBeanDefinition(mbd);mbdToUse.setBeanClass(resolvedClass);}// Prepare method overrides.//校驗和準備Bean中的方法覆蓋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.//如果Bean配置了初始化前和初始化后的處理器,則試圖返回一個需要創建Bean的代理對象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 ex) {// A previously detected exception with proper bean creation context already...throw ex;}catch (ImplicitlyAppearedSingletonException ex) {// An IllegalStateException to be communicated up to DefaultSingletonBeanRegistry...throw ex;}catch (Throwable ex) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);}}這段代碼分為以下幾個步驟:
1.判斷需要創建的Bean是否可以實例化,即是否可以通過當前的類加載器加載
2.校驗和準備Bean中的方法注入
3.如果Bean配置了初始化前和初始化后的處理器,則試圖返回一個需要創建Bean的代理對象
4.創建Bean
- 第1步:主要是獲取bean的class,并設置到BeanDefinition中
- 第2步:主要是處理方法注入
代碼:
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() + "]");}// 如果為1,則將注入方法標記為未重載// 注意:當有多個重載方法時,為了確定調用哪個具體的方法,Spring對重載方法的參數解析是很復雜的// 所以,如果注入方法沒有被重載這里就將其標記,省去了對方法參數的解析過程,直接調用即可else if (count == 1) {// Mark override as not overloaded, to avoid the overhead of arg type checking.mo.setOverloaded(false);}}代碼讀到這里,大家可能有疑問,從代碼上看明明是處理的方法重載,但是為什么處理的是方法注入呢?而且如果我們在bean里設置幾個方法重載的話,hasMethodOverrides()方法返回的是false。如果我們打開 AbstractBeanDefinition 類的 hasMethodOverrides() 方法,就能打消我們之前的疑問。
public boolean hasMethodOverrides() {return (this.methodOverrides != null && !this.methodOverrides.isEmpty());}其中methodOverrides是做什么的呢?通過類名AbstractBeanDefinition我們可以發現,該類是BeanDefinition的一個子類,那么它保存的應該是我們解析到的beanDefinition,spring在解析配置文件的時候,如果發現配置了replace-method或者lookup-method那么,就會對應的標簽解析,并存入到 AbstractBeanDefinition 的 methodOverrides 屬性中,那么當bean實例化的時候,如果檢測到了methodOverrides屬性不為空,則動態的為當前bean生成代理并使用相應的攔截器對bean做處理,這里大家只要把概念搞清楚即可。
- 第3步
主要是對bean前置后置處理器的處理,給 BeanPostProcessors 后置處理器一個返回代理對象的機會
詳細代碼:
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;}如果代理對象不為空,則直接返回代理對象,這一步驟有非常重要的作用,Spring 后續實現 AOP 就是基于這個地方判斷的。
這個方法核心就在于 applyBeanPostProcessorsBeforeInstantiation()和 applyBeanPostProcessorsAfterInitialization() 兩個方法,before 為實例化前的后處理器應用,after 為實例化后的后處理器應用。
- 第4步
doCreateBean()
創建Bean
//真正創建Bean的方法protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)throws BeanCreationException {// Instantiate the bean.//BeanWrapper是對Bean的包裝,其接口中所定義的功能很簡單包括設置獲取被包裝的對象,獲取被包裝bean的屬性描述器BeanWrapper instanceWrapper = null;if (mbd.isSingleton()) {//單例模式,刪除factoryBean緩存instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}if (instanceWrapper == null) {//使用合適的實例化策略來創建Bean:工廠方法、構造函數自動注入、簡單初始化instanceWrapper = createBeanInstance(beanName, mbd, args);}//從包裝類中獲取實例化的Beanfinal 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 {//調用PostProcessor后置處理器,修改 BeanDefinitionapplyMergedBeanDefinitionPostProcessors(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.isDebugEnabled()) {logger.debug("Eagerly caching bean '" + beanName +"' to allow for resolving potential circular references");}//這里是一個匿名內部類,為了防止循環引用,盡早持有對象的引用addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// Initialize the bean instance.//Bean對象的初始化,依賴注入在此觸發//這個exposedObject在初始化完成之后返回作為依賴注入完成后的BeanObject exposedObject = bean;try {//將Bean實例對象封裝,并且Bean定義中配置的屬性值賦值給實例對象populateBean(beanName, mbd, instanceWrapper);//初始化Bean對象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) {//獲取指定名稱的已注冊的單例模式Bean對象Object earlySingletonReference = getSingleton(beanName, false);if (earlySingletonReference != null) {//根據名稱獲取的已注冊的Bean和正在實例化的Bean是同一個if (exposedObject == bean) {//當前實例化的Bean初始化完成exposedObject = earlySingletonReference;}//當前Bean依賴其他Bean,并且當發生循環引用時不允許新創建實例對象else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {String[] dependentBeans = getDependentBeans(beanName);Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);//獲取當前Bean所依賴的其他Beanfor (String dependentBean : dependentBeans) {//對依賴Bean進行類型檢查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.//注冊完成依賴注入的Beantry {registerDisposableBeanIfNecessary(beanName, bean, mbd);}catch (BeanDefinitionValidationException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);}return exposedObject;}代碼很長,不過別慌,我們來按步驟分析一波
1.如果是單例模式,從factoryBeanInstanceCache 緩存中獲取BeanWrapper 實例對象并刪除緩存
2.調用createBeanInstance() 實例化 beanundefined(主要是將 BeanDefinition 轉換為BeanWrapper)
3.后置處理
4.單例模式的循環依賴處理
5.初始化 bean 實例對象undefined(屬性填充)
6.依賴檢查
7.注冊DisposableBean
doCreateBean() 完成 bean 的創建和初始化工作,內容太多,比較復雜,這里只列出大致流程。
本文轉自:https://cloud.tencent.com/developer/article/1503301
總結
以上是生活随笔為你收集整理的Spring Ioc 之 Bean的加载(3):createBean()的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何评价一个产品经理工作做的好坏?
- 下一篇: 2021年京东小魔方年中新品消费趋势报告