程式碼入口
上文【Spring原始碼分析】Bean載入流程概覽,比較詳細地分析了Spring上下文載入的程式碼入口,並且在AbstractApplicationContext的refresh方法中,點出了finishBeanFactoryInitialization方法完成了對於所有非懶載入的Bean的初始化。
finishBeanFactoryInitialization方法中呼叫了DefaultListableBeanFactory的preInstantiateSingletons方法,本文針對preInstantiateSingletons進行分析,解讀一下Spring是如何初始化Bean例項物件出來的。
DefaultListableBeanFactory的preInstantiateSingletons方法
DefaultListableBeanFactory的preInstantiateSingletons方法,顧名思義,初始化所有的單例Bean,看一下方法的定義:
1 public void preInstantiateSingletons() throws BeansException { 2 if (this.logger.isInfoEnabled()) { 3 this.logger.info("Pre-instantiating singletons in " + this); 4 } 5 synchronized (this.beanDefinitionMap) { 6 // Iterate over a copy to allow for init methods which in turn register new bean definitions. 7 // While this may not be part of the regular factory bootstrap, it does otherwise work fine. 8 List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames); 9 for (String beanName : beanNames) { 10 RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); 11 if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { 12 if (isFactoryBean(beanName)) { 13 final FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName); 14 boolean isEagerInit; 15 if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { 16 isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() { 17 public Boolean run() { 18 return ((SmartFactoryBean) factory).isEagerInit(); 19 } 20 }, getAccessControlContext()); 21 } 22 else { 23 isEagerInit = (factory instanceof SmartFactoryBean && 24 ((SmartFactoryBean) factory).isEagerInit()); 25 } 26 if (isEagerInit) { 27 getBean(beanName); 28 } 29 } 30 else { 31 getBean(beanName); 32 } 33 } 34 } 35 } 36 }
這裡先解釋一下getMergedLocalBeanDefinition方法的含義,因為這個方法會常常看到。Bean定義公共的抽象類是AbstractBeanDefinition,普通的Bean在Spring載入Bean定義的時候,例項化出來的是GenericBeanDefinition,而Spring上下文包括例項化所有Bean用的AbstractBeanDefinition是RootBeanDefinition,這時候就使用getMergedLocalBeanDefinition方法做了一次轉化,將非RootBeanDefinition轉換為RootBeanDefinition以供後續操作。
解釋完了getMergedLocalBeanDefinition方法的作用,第1行~第10行的程式碼就沒什麼好說的了,根據beanName拿到RootBeanDefinition而已。由於此方法例項化的是所有非懶載入的單例Bean,因此要例項化Bean,必須滿足11行的三個定義:
(1)不是抽象的
(2)必須是單例的
(3)必須是非懶載入的
接著簡單看一下第12行~第29行的程式碼,這段程式碼主要做的是一件事情:首先判斷一下Bean是否FactoryBean的實現,接著判斷Bean是否SmartFactoryBean的實現,假如Bean是SmartFactoryBean的實現並且eagerInit(這個單詞字面意思是渴望載入,找不到一個好的詞語去翻譯,意思就是定義了這個Bean需要立即載入的意思)的話,會立即例項化這個Bean。Java開發人員不需要關注這段程式碼,因為SmartFactoryBean基本不會用到,我翻譯一下Spring官網對於SmartFactoryBean的定義描述:
- FactoryBean介面的擴充套件介面。介面實現並不表示是否總是返回單獨的例項物件,比如FactoryBean.isSingleton()實現返回false的情況並不清晰地表示每次返回的都是單獨的例項物件
- 不實現這個擴充套件介面的簡單FactoryBean的實現,FactoryBean.isSingleton()實現返回false總是簡單地告訴我們每次返回的都是單獨的例項物件,暴露出來的物件只能夠通過命令訪問
- 注意:這個介面是一個有特殊用途的介面,主要用於框架內部使用與Spring相關。通常,應用提供的FactoryBean介面實現應當只需要實現簡單的FactoryBean介面即可,新方法應當加入到擴充套件介面中去
程式碼示例
為了後面的程式碼分析方便,事先我定義一個Bean:
1 package org.xrq.action; 2 3 import org.springframework.beans.factory.BeanClassLoaderAware; 4 import org.springframework.beans.factory.BeanNameAware; 5 import org.springframework.beans.factory.InitializingBean; 6 7 public class MultiFunctionBean implements InitializingBean, BeanNameAware, BeanClassLoaderAware { 8 9 private int propertyA; 10 11 private int propertyB; 12 13 public int getPropertyA() { 14 return propertyA; 15 } 16 17 public void setPropertyA(int propertyA) { 18 this.propertyA = propertyA; 19 } 20 21 public int getPropertyB() { 22 return propertyB; 23 } 24 25 public void setPropertyB(int propertyB) { 26 this.propertyB = propertyB; 27 } 28 29 public void initMethod() { 30 System.out.println("Enter MultiFunctionBean.initMethod()"); 31 } 32 33 @Override 34 public void setBeanClassLoader(ClassLoader classLoader) { 35 System.out.println("Enter MultiFunctionBean.setBeanClassLoader(ClassLoader classLoader)"); 36 } 37 38 @Override 39 public void setBeanName(String name) { 40 System.out.println("Enter MultiFunctionBean.setBeanName(String name)"); 41 } 42 43 @Override 44 public void afterPropertiesSet() throws Exception { 45 System.out.println("Enter MultiFunctionBean.afterPropertiesSet()"); 46 } 47 48 @Override 49 public String toString() { 50 return "MultiFunctionBean [propertyA=" + propertyA + ", propertyB=" + propertyB + "]"; 51 } 52 53 }
定義對應的spring.xml:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> 6 7 <bean id="multiFunctionBean" class="org.xrq.action.MultiFunctionBean" init-method="initMethod" /> 8 9 </beans>
利用這個MultiFunctionBean,我們可以用來探究Spring載入Bean的多種機制。
doGetBean方法構造Bean流程
上面把getBean之外的程式碼都分析了一下,看程式碼就可以知道,獲取Bean物件例項,都是通過getBean方法,getBean方法最終呼叫的是DefaultListableBeanFactory的父類AbstractBeanFactory類的doGetBean方法,因此這部分重點分析一下doGetBean方法是如何構造出一個單例的Bean的。
看一下doGetBean方法的程式碼實現,比較長:
1 protected <T> T doGetBean( 2 final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) 3 throws BeansException { 4 5 final String beanName = transformedBeanName(name); 6 Object bean; 7 8 // Eagerly check singleton cache for manually registered singletons. 9 Object sharedInstance = getSingleton(beanName); 10 if (sharedInstance != null && args == null) { 11 if (logger.isDebugEnabled()) { 12 if (isSingletonCurrentlyInCreation(beanName)) { 13 logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + 14 "' that is not fully initialized yet - a consequence of a circular reference"); 15 } 16 else { 17 logger.debug("Returning cached instance of singleton bean '" + beanName + "'"); 18 } 19 } 20 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); 21 } 22 23 else { 24 // Fail if we're already creating this bean instance: 25 // We're assumably within a circular reference. 26 if (isPrototypeCurrentlyInCreation(beanName)) { 27 throw new BeanCurrentlyInCreationException(beanName); 28 } 29 30 // Check if bean definition exists in this factory. 31 BeanFactory parentBeanFactory = getParentBeanFactory(); 32 if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { 33 // Not found -> check parent. 34 String nameToLookup = originalBeanName(name); 35 if (args != null) { 36 // Delegation to parent with explicit args. 37 return (T) parentBeanFactory.getBean(nameToLookup, args); 38 } 39 else { 40 // No args -> delegate to standard getBean method. 41 return parentBeanFactory.getBean(nameToLookup, requiredType); 42 } 43 } 44 45 if (!typeCheckOnly) { 46 markBeanAsCreated(beanName); 47 } 48 49 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); 50 checkMergedBeanDefinition(mbd, beanName, args); 51 52 // Guarantee initialization of beans that the current bean depends on. 53 String[] dependsOn = mbd.getDependsOn(); 54 if (dependsOn != null) { 55 for (String dependsOnBean : dependsOn) { 56 getBean(dependsOnBean); 57 registerDependentBean(dependsOnBean, beanName); 58 } 59 } 60 61 // Create bean instance. 62 if (mbd.isSingleton()) { 63 sharedInstance = getSingleton(beanName, new ObjectFactory() { 64 public Object getObject() throws BeansException { 65 try { 66 return createBean(beanName, mbd, args); 67 } 68 catch (BeansException ex) { 69 // Explicitly remove instance from singleton cache: It might have been put there 70 // eagerly by the creation process, to allow for circular reference resolution. 71 // Also remove any beans that received a temporary reference to the bean. 72 destroySingleton(beanName); 73 throw ex; 74 } 75 } 76 }); 77 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); 78 } 79 80 else if (mbd.isPrototype()) { 81 // It's a prototype -> create a new instance. 82 Object prototypeInstance = null; 83 try { 84 beforePrototypeCreation(beanName); 85 prototypeInstance = createBean(beanName, mbd, args); 86 } 87 finally { 88 afterPrototypeCreation(beanName); 89 } 90 bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); 91 } 92 93 else { 94 String scopeName = mbd.getScope(); 95 final Scope scope = this.scopes.get(scopeName); 96 if (scope == null) { 97 throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'"); 98 } 99 try { 100 Object scopedInstance = scope.get(beanName, new ObjectFactory() { 101 public Object getObject() throws BeansException { 102 beforePrototypeCreation(beanName); 103 try { 104 return createBean(beanName, mbd, args); 105 } 106 finally { 107 afterPrototypeCreation(beanName); 108 } 109 } 110 }); 111 bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); 112 } 113 catch (IllegalStateException ex) { 114 throw new BeanCreationException(beanName, 115 "Scope '" + scopeName + "' is not active for the current thread; " + 116 "consider defining a scoped proxy for this bean if you intend to refer to it from a singleton", 117 ex); 118 } 119 } 120 } 121 122 // Check if required type matches the type of the actual bean instance. 123 if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) { 124 try { 125 return getTypeConverter().convertIfNecessary(bean, requiredType); 126 } 127 catch (TypeMismatchException ex) { 128 if (logger.isDebugEnabled()) { 129 logger.debug("Failed to convert bean '" + name + "' to required type [" + 130 ClassUtils.getQualifiedName(requiredType) + "]", ex); 131 } 132 throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); 133 } 134 } 135 return (T) bean; 136 }
首先第9行~第21行的程式碼,第9行的程式碼就不進去看了,簡單說一下:首先檢查一下本地的單例快取是否已經載入過Bean,沒有的話再檢查earlySingleton快取是否已經載入過Bean(又是early,不好找到詞語翻譯),沒有的話執行後面的邏輯。
接著第26行~第50行,這裡執行的都是一些基本的檢查和簡單的操作,包括bean是否是prototype的(prototype的Bean當前建立會丟擲異常)、是否抽象的、將beanName加入alreadyCreated這個Set中等。
接著第53行~第59行,我們經常在bean標籤中看到depends-on這個屬性,就是通過這段保證了depends-on依賴的Bean會優先於當前Bean被載入。
接著第62行~第78行、第80行~第91行、第93行~第120行有三個判斷,顯然上面的MultiFunctionBean是一個單例的Bean也是本文探究的重點,因此執行第62行~第78行的邏輯。getSingleton方法不貼了,有一些前置的判斷,很簡單的邏輯,重點就是呼叫了ObjectFactory的getObject()方法來獲取到單例Bean物件,方法的實現是呼叫了createBean方法,createBean方法是AbstractBeanFactory的子類AbstractAutowireCapableBeanFactory的一個方法,看一下它的方法實現:
1 protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) 2 throws BeanCreationException { 3 4 if (logger.isDebugEnabled()) { 5 logger.debug("Creating instance of bean '" + beanName + "'"); 6 } 7 // Make sure bean class is actually resolved at this point. 8 resolveBeanClass(mbd, beanName); 9 10 // Prepare method overrides. 11 try { 12 mbd.prepareMethodOverrides(); 13 } 14 catch (BeanDefinitionValidationException ex) { 15 throw new BeanDefinitionStoreException(mbd.getResourceDescription(), 16 beanName, "Validation of method overrides failed", ex); 17 } 18 19 try { 20 // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. 21 Object bean = resolveBeforeInstantiation(beanName, mbd); 22 if (bean != null) { 23 return bean; 24 } 25 } 26 catch (Throwable ex) { 27 throw new BeanCreationException(mbd.getResourceDescription(), beanName, 28 "BeanPostProcessor before instantiation of bean failed", ex); 29 } 30 31 Object beanInstance = doCreateBean(beanName, mbd, args); 32 if (logger.isDebugEnabled()) { 33 logger.debug("Finished creating instance of bean '" + beanName + "'"); 34 } 35 return beanInstance; 36 }
前面的程式碼都沒什麼意義,程式碼執行到第31行:
1 protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) { 2 // Instantiate the bean. 3 BeanWrapper instanceWrapper = null; 4 if (mbd.isSingleton()) { 5 instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); 6 } 7 if (instanceWrapper == null) { 8 instanceWrapper = createBeanInstance(beanName, mbd, args); 9 } 10 final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null); 11 Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null); 12 13 // Allow post-processors to modify the merged bean definition. 14 synchronized (mbd.postProcessingLock) { 15 if (!mbd.postProcessed) { 16 applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); 17 mbd.postProcessed = true; 18 } 19 } 20 21 // Eagerly cache singletons to be able to resolve circular references 22 // even when triggered by lifecycle interfaces like BeanFactoryAware. 23 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && 24 isSingletonCurrentlyInCreation(beanName)); 25 if (earlySingletonExposure) { 26 if (logger.isDebugEnabled()) { 27 logger.debug("Eagerly caching bean '" + beanName + 28 "' to allow for resolving potential circular references"); 29 } 30 addSingletonFactory(beanName, new ObjectFactory() { 31 public Object getObject() throws BeansException { 32 return getEarlyBeanReference(beanName, mbd, bean); 33 } 34 }); 35 } 36 37 // Initialize the bean instance. 38 Object exposedObject = bean; 39 try { 40 populateBean(beanName, mbd, instanceWrapper); 41 if (exposedObject != null) { 42 exposedObject = initializeBean(beanName, exposedObject, mbd); 43 } 44 } 45 catch (Throwable ex) { 46 if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { 47 throw (BeanCreationException) ex; 48 } 49 else { 50 throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); 51 } 52 } 53 54 if (earlySingletonExposure) { 55 Object earlySingletonReference = getSingleton(beanName, false); 56 if (earlySingletonReference != null) { 57 if (exposedObject == bean) { 58 exposedObject = earlySingletonReference; 59 } 60 else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { 61 String[] dependentBeans = getDependentBeans(beanName); 62 Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length); 63 for (String dependentBean : dependentBeans) { 64 if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { 65 actualDependentBeans.add(dependentBean); 66 } 67 } 68 if (!actualDependentBeans.isEmpty()) { 69 throw new BeanCurrentlyInCreationException(beanName, 70 "Bean with name '" + beanName + "' has been injected into other beans [" + 71 StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + 72 "] in its raw version as part of a circular reference, but has eventually been " + 73 "wrapped. This means that said other beans do not use the final version of the " + 74 "bean. This is often the result of over-eager type matching - consider using " + 75 "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example."); 76 } 77 } 78 } 79 } 80 81 // Register bean as disposable. 82 try { 83 registerDisposableBeanIfNecessary(beanName, bean, mbd); 84 } 85 catch (BeanDefinitionValidationException ex) { 86 throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); 87 } 88 89 return exposedObject; 90 }
程式碼跟蹤到這裡,已經到了主流程,接下來分段分析doCreateBean方法的程式碼。
建立Bean例項
第8行的createBeanInstance方法,會建立出Bean的例項,幷包裝為BeanWrapper,看一下createBeanInstance方法,只貼最後一段比較關鍵的:
1 // Need to determine the constructor... 2 Constructor[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); 3 if (ctors != null || 4 mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR || 5 mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { 6 return autowireConstructor(beanName, mbd, ctors, args); 7 } 8 9 // No special handling: simply use no-arg constructor. 10 return instantiateBean(beanName, mbd);
意思是bean標籤使用建構函式注入屬性的話,執行第6行,否則執行第10行。MultiFunctionBean使用預設建構函式,使用setter注入屬性,因此執行第10行程式碼:
1 protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) { 2 try { 3 Object beanInstance; 4 final BeanFactory parent = this; 5 if (System.getSecurityManager() != null) { 6 beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() { 7 public Object run() { 8 return getInstantiationStrategy().instantiate(mbd, beanName, parent); 9 } 10 }, getAccessControlContext()); 11 } 12 else { 13 beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent); 14 } 15 BeanWrapper bw = new BeanWrapperImpl(beanInstance); 16 initBeanWrapper(bw); 17 return bw; 18 } 19 catch (Throwable ex) { 20 throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex); 21 } 22 }
程式碼執行到13行:
1 public Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) { 2 // Don't override the class with CGLIB if no overrides. 3 if (beanDefinition.getMethodOverrides().isEmpty()) { 4 Constructor<?> constructorToUse; 5 synchronized (beanDefinition.constructorArgumentLock) { 6 constructorToUse = (Constructor<?>) beanDefinition.resolvedConstructorOrFactoryMethod; 7 if (constructorToUse == null) { 8 final Class clazz = beanDefinition.getBeanClass(); 9 if (clazz.isInterface()) { 10 throw new BeanInstantiationException(clazz, "Specified class is an interface"); 11 } 12 try { 13 if (System.getSecurityManager() != null) { 14 constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor>() { 15 public Constructor run() throws Exception { 16 return clazz.getDeclaredConstructor((Class[]) null); 17 } 18 }); 19 } 20 else { 21 constructorToUse = clazz.getDeclaredConstructor((Class[]) null); 22 } 23 beanDefinition.resolvedConstructorOrFactoryMethod = constructorToUse; 24 } 25 catch (Exception ex) { 26 throw new BeanInstantiationException(clazz, "No default constructor found", ex); 27 } 28 } 29 } 30 return BeanUtils.instantiateClass(constructorToUse); 31 } 32 else { 33 // Must generate CGLIB subclass. 34 return instantiateWithMethodInjection(beanDefinition, beanName, owner); 35 } 36 }
整段程式碼都在做一件事情,就是選擇一個使用的建構函式。當然第9行順帶做了一個判斷:例項化一個介面將報錯。
最後呼叫到30行,看一下程式碼:
1 public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException { 2 Assert.notNull(ctor, "Constructor must not be null"); 3 try { 4 ReflectionUtils.makeAccessible(ctor); 5 return ctor.newInstance(args); 6 } 7 catch (InstantiationException ex) { 8 throw new BeanInstantiationException(ctor.getDeclaringClass(), 9 "Is it an abstract class?", ex); 10 } 11 catch (IllegalAccessException ex) { 12 throw new BeanInstantiationException(ctor.getDeclaringClass(), 13 "Is the constructor accessible?", ex); 14 } 15 catch (IllegalArgumentException ex) { 16 throw new BeanInstantiationException(ctor.getDeclaringClass(), 17 "Illegal arguments for constructor", ex); 18 } 19 catch (InvocationTargetException ex) { 20 throw new BeanInstantiationException(ctor.getDeclaringClass(), 21 "Constructor threw exception", ex.getTargetException()); 22 } 23 }
通過反射生成Bean的例項。看到前面有一步makeAccessible,這意味著即使Bean的建構函式是private、protected的,依然不影響Bean的構造。
最後注意一下,這裡被例項化出來的Bean並不會直接返回,而是會被包裝為BeanWrapper繼續在後面使用。