初探getBean()方法
在使用Spring的時候可以通過如下方式呼叫getBean方法來獲取某個Bean:
User user = context.getBean(User.class);
AbstractApplicationContext中定義了一系列getBean方法,程式碼如下:
//--------------------------------------------------------------------- // Implementation of BeanFactory interface //--------------------------------------------------------------------- @Override public Object getBean(String name) throws BeansException { assertBeanFactoryActive(); return getBeanFactory().getBean(name); } @Override public <T> T getBean(String name, Class<T> requiredType) throws BeansException { assertBeanFactoryActive(); return getBeanFactory().getBean(name, requiredType); } @Override public Object getBean(String name, Object... args) throws BeansException { assertBeanFactoryActive(); return getBeanFactory().getBean(name, args); } @Override public <T> T getBean(Class<T> requiredType) throws BeansException { assertBeanFactoryActive(); return getBeanFactory().getBean(requiredType); } @Override public <T> T getBean(Class<T> requiredType, Object... args) throws BeansException { assertBeanFactoryActive(); return getBeanFactory().getBean(requiredType, args); }
解讀:
上述getBean方法本質上是通過BeanFactory的getBean方法來實現的。
Note:
AbstractApplicationContext中getBeanFactory為抽象方法,程式碼如下:
/** * Subclasses must return their internal bean factory here. They should implement the * lookup efficiently, so that it can be called repeatedly without a performance penalty. * <p>Note: Subclasses should check whether the context is still active before * returning the internal bean factory. The internal factory should generally be * considered unavailable once the context has been closed. * @return this application context's internal bean factory (never {@code null}) * @throws IllegalStateException if the context does not hold an internal bean factory yet * (usually if {@link #refresh()} has never been called) or if the context has been * closed already * @see #refreshBeanFactory() * @see #closeBeanFactory() */ @Override public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
解讀:
此方法的具體邏輯由子類實現。
Note:
此方法的返回值型別是ConfigurableListableBeanFactory。
類圖
下圖為BeanFactory相關類圖:
解讀:
- HierarhicalBeanFactory
該介面允許子容器訪問父容器,其中方法如下圖所示:
- ListableBeanFactory
該介面定義了訪問容器中 Bean 基本資訊的若干方法,如:檢視 Bean 的個數,獲取某一型別 Bean 的配置名,其中方法如下圖所示:
- ConfigurableBeanFactory
該介面增強了 IoC 容器的可定製性,它定義了設定類裝載器、屬性編輯器、容器初始化後置處理器等方法,下圖僅列出了其中部分方法:
- AutowireCapableBeanFactory
該介面定義了將容器中的 Bean 按某種規則(如:按名稱匹配、按型別匹配)進行自動裝配的方法,其中方法如下圖所示:
Note:
從上述類圖可以發現ConfigurableListableBeanFactory的唯一實現類是DefaultListableBeanFactory。
深入getBean()方法
BeanFactory介面中的方法如下圖所示:
解讀:
這幾個getBean方法由AbstractBeanFactory、DefaultListableBeanFactory實現
(1)org.springframework.beans.factory.support.AbstractBeanFactory中getBean()方法的定義如下:
//--------------------------------------------------------------------- // Implementation of BeanFactory interface //--------------------------------------------------------------------- @Override public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); } @Override public <T> T getBean(String name, Class<T> requiredType) throws BeansException { return doGetBean(name, requiredType, null, false); } @Override public Object getBean(String name, Object... args) throws BeansException { return doGetBean(name, null, args, false); }
(2)org.springframework.beans.factory.support.DefaultListableBeanFactory中getBean()方法的定義如下:
//--------------------------------------------------------------------- // Implementation of remaining BeanFactory methods //--------------------------------------------------------------------- @Override public <T> T getBean(Class<T> requiredType) throws BeansException { return getBean(requiredType, (Object[]) null); } @SuppressWarnings("unchecked") @Override public <T> T getBean(Class<T> requiredType, @Nullable Object... args) throws BeansException { Assert.notNull(requiredType, "Required type must not be null"); Object resolved = resolveBean(ResolvableType.forRawClass(requiredType), args, false); if (resolved == null) { throw new NoSuchBeanDefinitionException(requiredType); } return (T) resolved; }
AbstractBeanFactory
AbstractBeanFactory中的getBean方法均呼叫了doGetBean(...)方法,該方法的定義如下:
/** * Return an instance, which may be shared or independent, of the specified bean. * @param name the name of the bean to retrieve * @param requiredType the required type of the bean to retrieve * @param args arguments to use when creating a bean instance using explicit arguments * (only applied when creating a new instance as opposed to retrieving an existing one) * @param typeCheckOnly whether the instance is obtained for a type check, * not for actual use * @return an instance of the bean * @throws BeansException if the bean could not be created */ @SuppressWarnings("unchecked") protected <T> T doGetBean( String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException { String beanName = transformedBeanName(name); Object beanInstance; // Eagerly check singleton cache for manually registered singletons. Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { if (logger.isTraceEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) { logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference"); } else { logger.trace("Returning cached instance of singleton bean '" + beanName + "'"); } } beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { // Fail if we're already creating this bean instance: // We're assumably within a circular reference. if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } // Check if bean definition exists in this factory. BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // Not found -> check parent. String nameToLookup = originalBeanName(name); if (parentBeanFactory instanceof AbstractBeanFactory) { return ((AbstractBeanFactory) parentBeanFactory).doGetBean( nameToLookup, requiredType, args, typeCheckOnly); } else if (args != null) { // Delegation to parent with explicit args. return (T) parentBeanFactory.getBean(nameToLookup, args); } else if (requiredType != null) { // No args -> delegate to standard getBean method. return parentBeanFactory.getBean(nameToLookup, requiredType); } else { return (T) parentBeanFactory.getBean(nameToLookup); } } if (!typeCheckOnly) { markBeanAsCreated(beanName); } StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate") .tag("beanName", name); try { if (requiredType != null) { beanCreation.tag("beanType", requiredType::toString); } RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); // Guarantee initialization of beans that the current bean depends on. String[] dependsOn = mbd.getDependsOn(); 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); try { getBean(dep); } catch (NoSuchBeanDefinitionException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", ex); } } } // Create bean instance. if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { 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; } }); beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } else if (mbd.isPrototype()) { // It's a prototype -> create a new instance. Object prototypeInstance = null; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } else { String scopeName = mbd.getScope(); if (!StringUtils.hasLength(scopeName)) { throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'"); } 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, () -> { beforePrototypeCreation(beanName); try { return createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } }); beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } catch (IllegalStateException ex) { throw new ScopeNotActiveException(beanName, scopeName, ex); } } } catch (BeansException ex) { beanCreation.tag("exception", ex.getClass().toString()); beanCreation.tag("message", String.valueOf(ex.getMessage())); cleanupAfterBeanCreationFailure(beanName); throw ex; } finally { beanCreation.end(); } } return adaptBeanInstance(name, beanInstance, requiredType); }
解讀:
上述方法呼叫了createBean方法,對應的引數分別是beanName、mbd、args(建議重點關注一下mbd,RootBeanDefinition型別)。
Note:
Spring 配置檔案中每一個 bean 節點元素在 Spring 容器裡都由一個BeanDefinition 物件表示,它包含了某個 Bean 的具體資訊。
BeanDefinition相關類圖如下:
createBean方法的定義如下:
/** * Create a bean instance for the given merged bean definition (and arguments). * The bean definition will already have been merged with the parent definition * in case of a child definition. * <p>All bean retrieval methods delegate to this method for actual bean creation. * @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 */ protected abstract Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException;
解讀:
上述createBean方法為抽象方法,由子類實現。
AbstractAutowireCapableBeanFactory —— createBean方法
AbstractAutowireCapableBeanFactory中CreateBean方法
/** * Central method of this class: creates a bean instance, * populates the bean instance, applies post-processors, etc. * @see #doCreateBean */ @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<?> resolvedClass = resolveBeanClass(mbd, beanName); if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) { mbdToUse = new RootBeanDefinition(mbd); mbdToUse.setBeanClass(resolvedClass); } // Prepare method overrides. 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. 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); } Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isDebugEnabled()) { logger.debug("Finished creating instance of bean '" + beanName + "'"); } return beanInstance; }
解讀:
一般情況下,某個型別的Bean是由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. * @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 Object[] args) { // Instantiate the bean. BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { instanceWrapper = createBeanInstance(beanName, mbd, args); } final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null); Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null); // Allow post-processors to modify the merged bean definition. synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); 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, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { return getEarlyBeanReference(beanName, mbd, bean); } }); } // Initialize the bean instance. Object exposedObject = bean; try { populateBean(beanName, mbd, instanceWrapper); if (exposedObject != null) { 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); if (earlySingletonReference != null) { if (exposedObject == bean) { exposedObject = earlySingletonReference; } else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { String[] dependentBeans = getDependentBeans(beanName); Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length); for (String dependentBean : dependentBeans) { 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. try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); } return exposedObject; }
解讀:
上述方法涵蓋了Bean生命週期(即:例項化 -> 屬性賦值 -> 初始化 -> 銷燬)中的前三個階段