doCreateBean method
Above [Spring Source Analysis] Bean instantiation process without lazy loading (Part I) In this paper, we analyze the Bean initialization process of the singleton, and trace the code into the mainstream process, and see how the Bean is instantiated. First, paste the doCreateBean method code of AbstractAutowire Capable BeanFactory:
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 }
Let's continue to analyze the process of initializing a Bean, and skip the less important process.
Attribute injection
Attribute injection code is easy to find, you can see 40 lines, named populate Bean, that is, the meaning of filling beans, to see the code implementation:
1 protected void populateBean(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw) { 2 PropertyValues pvs = mbd.getPropertyValues(); 3 4 if (bw == null) { 5 if (!pvs.isEmpty()) { 6 throw new BeanCreationException( 7 mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance"); 8 } 9 else { 10 // Skip property population phase for null instance. 11 return; 12 } 13 } 14 15 // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the 16 // state of the bean before properties are set. This can be used, for example, 17 // to support styles of field injection. 18 boolean continueWithPropertyPopulation = true; 19 20 if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { 21 for (BeanPostProcessor bp : getBeanPostProcessors()) { 22 if (bp instanceof InstantiationAwareBeanPostProcessor) { 23 InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; 24 if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { 25 continueWithPropertyPopulation = false; 26 break; 27 } 28 } 29 } 30 } 31 32 if (!continueWithPropertyPopulation) { 33 return; 34 } 35 36 if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME || 37 mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { 38 MutablePropertyValues newPvs = new MutablePropertyValues(pvs); 39 40 // Add property values based on autowire by name if applicable. 41 if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) { 42 autowireByName(beanName, mbd, bw, newPvs); 43 } 44 45 // Add property values based on autowire by type if applicable. 46 if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { 47 autowireByType(beanName, mbd, bw, newPvs); 48 } 49 50 pvs = newPvs; 51 } 52 53 boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors(); 54 boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE); 55 56 if (hasInstAwareBpps || needsDepCheck) { 57 PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw); 58 if (hasInstAwareBpps) { 59 for (BeanPostProcessor bp : getBeanPostProcessors()) { 60 if (bp instanceof InstantiationAwareBeanPostProcessor) { 61 InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; 62 pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); 63 if (pvs == null) { 64 return; 65 } 66 } 67 } 68 } 69 if (needsDepCheck) { 70 checkDependencies(beanName, mbd, filteredPds, pvs); 71 } 72 } 73 74 applyPropertyValues(beanName, mbd, bw, pvs); 75 }
This code is a bit deep, follow the 74-line applyPropertyValues method, and the last pvs implementation class is MutablePropertyValues, which holds a List < PropertyValue > and each PropertyValue contains the property name and value of the Bean property. 74 lines of code are implemented as follows:
1 protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) { 2 if (pvs == null || pvs.isEmpty()) { 3 return; 4 } 5 6 MutablePropertyValues mpvs = null; 7 List<PropertyValue> original; 8 9 if (System.getSecurityManager()!= null) { 10 if (bw instanceof BeanWrapperImpl) { 11 ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext()); 12 } 13 } 14 15 if (pvs instanceof MutablePropertyValues) { 16 mpvs = (MutablePropertyValues) pvs; 17 if (mpvs.isConverted()) { 18 // Shortcut: use the pre-converted values as-is. 19 try { 20 bw.setPropertyValues(mpvs); 21 return; 22 } 23 catch (BeansException ex) { 24 throw new BeanCreationException( 25 mbd.getResourceDescription(), beanName, "Error setting property values", ex); 26 } 27 } 28 original = mpvs.getPropertyValueList(); 29 } 30 else { 31 original = Arrays.asList(pvs.getPropertyValues()); 32 } 33 34 TypeConverter converter = getCustomTypeConverter(); 35 if (converter == null) { 36 converter = bw; 37 } 38 BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter); 39 40 // Create a deep copy, resolving any references for values. 41 List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size()); 42 boolean resolveNecessary = false; 43 for (PropertyValue pv : original) { 44 if (pv.isConverted()) { 45 deepCopy.add(pv); 46 } 47 else { 48 String propertyName = pv.getName(); 49 Object originalValue = pv.getValue(); 50 Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue); 51 Object convertedValue = resolvedValue; 52 boolean convertible = bw.isWritableProperty(propertyName) && 53 !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName); 54 if (convertible) { 55 convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter); 56 } 57 // Possibly store converted value in merged bean definition, 58 // in order to avoid re-conversion for every created bean instance. 59 if (resolvedValue == originalValue) { 60 if (convertible) { 61 pv.setConvertedValue(convertedValue); 62 } 63 deepCopy.add(pv); 64 } 65 else if (convertible && originalValue instanceof TypedStringValue && 66 !((TypedStringValue) originalValue).isDynamic() && 67 !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) { 68 pv.setConvertedValue(convertedValue); 69 deepCopy.add(pv); 70 } 71 else { 72 resolveNecessary = true; 73 deepCopy.add(new PropertyValue(pv, convertedValue)); 74 } 75 } 76 } 77 if (mpvs != null && !resolveNecessary) { 78 mpvs.setConverted(); 79 } 80 81 // Set our (possibly massaged) deep copy. 82 try { 83 bw.setPropertyValues(new MutablePropertyValues(deepCopy)); 84 } 85 catch (BeansException ex) { 86 throw new BeanCreationException( 87 mbd.getResourceDescription(), beanName, "Error setting property values", ex); 88 } 89 }
Then a deep copy is made in lines 41 to 76 (just called deep copy, which is actually traversing Property Value and assigning one by one to a new List instead of a Clone in Java semantics, where deep copy is used to parse all references to Values values), assigning Property Value one by one to a new List, called deepCopy. Finally, 83 lines are executed for replication, bw is BeanWrapper, which holds a Bean wrapper class for the Bean instance. Take a look at the code implementation:
1 public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid) 2 throws BeansException { 3 4 List<PropertyAccessException> propertyAccessExceptions = null; 5 List<PropertyValue> propertyValues = (pvs instanceof MutablePropertyValues ? 6 ((MutablePropertyValues) pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues())); 7 for (PropertyValue pv : propertyValues) { 8 try { 9 // This method may throw any BeansException, which won't be caught 10 // here, if there is a critical failure such as no matching field. 11 // We can attempt to deal only with less serious exceptions. 12 setPropertyValue(pv); 13 } 14 catch (NotWritablePropertyException ex) { 15 if (!ignoreUnknown) { 16 throw ex; 17 } 18 // Otherwise, just ignore it and continue... 19 } 20 catch (NullValueInNestedPathException ex) { 21 if (!ignoreInvalid) { 22 throw ex; 23 } 24 // Otherwise, just ignore it and continue... 25 } 26 catch (PropertyAccessException ex) { 27 if (propertyAccessExceptions == null) { 28 propertyAccessExceptions = new LinkedList<PropertyAccessException>(); 29 } 30 propertyAccessExceptions.add(ex); 31 } 32 } 33 34 // If we encountered individual exceptions, throw the composite exception. 35 if (propertyAccessExceptions != null) { 36 PropertyAccessException[] paeArray = 37 propertyAccessExceptions.toArray(new PropertyAccessException[propertyAccessExceptions.size()]); 38 throw new PropertyBatchUpdateException(paeArray); 39 } 40 }
This code is nothing special. Go through the previous deepCopy, take each Property Value, and execute the setProperty Value on line 12:
1 public void setPropertyValue(PropertyValue pv) throws BeansException { 2 PropertyTokenHolder tokens = (PropertyTokenHolder) pv.resolvedTokens; 3 if (tokens == null) { 4 String propertyName = pv.getName(); 5 BeanWrapperImpl nestedBw; 6 try { 7 nestedBw = getBeanWrapperForPropertyPath(propertyName); 8 } 9 catch (NotReadablePropertyException ex) { 10 throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName, 11 "Nested property in path '" + propertyName + "' does not exist", ex); 12 } 13 tokens = getPropertyNameTokens(getFinalPath(nestedBw, propertyName)); 14 if (nestedBw == this) { 15 pv.getOriginalPropertyValue().resolvedTokens = tokens; 16 } 17 nestedBw.setPropertyValue(tokens, pv); 18 } 19 else { 20 setPropertyValue(tokens, pv); 21 } 22 }
Find a suitable BeanWrapper, which is itself, and then execute the 17-line setPropertyValue method to the last step. The method is very long, intercepting the core section:
1 final Method writeMethod = (pd instanceof GenericTypeAwarePropertyDescriptor ? 2 ((GenericTypeAwarePropertyDescriptor) pd).getWriteMethodForActualAccess() : 3 pd.getWriteMethod()); 4 if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers()) && !writeMethod.isAccessible()) { 5 if (System.getSecurityManager()!= null) { 6 AccessController.doPrivileged(new PrivilegedAction<Object>() { 7 public Object run() { 8 writeMethod.setAccessible(true); 9 return null; 10 } 11 }); 12 } 13 else { 14 writeMethod.setAccessible(true); 15 } 16 } 17 final Object value = valueToApply; 18 if (System.getSecurityManager() != null) { 19 try { 20 AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { 21 public Object run() throws Exception { 22 writeMethod.invoke(object, value); 23 return null; 24 } 25 }, acc); 26 } 27 catch (PrivilegedActionException ex) { 28 throw ex.getException(); 29 } 30 } 31 else { 32 writeMethod.invoke(this.object, value); 33 }
The general process consists of two steps:
(1) Get the write method and set its visibility to true
(2) Get the Value value and invoke the write method on the Bean by reflection
This completes the setting of the Bean property values.
Aware injection
Next comes Aware injection. When using Spring, we implement BeanNameAware interface, BeanFactoryAware interface, etc. with our own beans. We rely on the container to inject the name of the current Bean or the Bean factory. The code implementation first traces back to the 42-line initializeBean method of the doCreateBean method above:
1 protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) { 2 if (System.getSecurityManager() != null) { 3 AccessController.doPrivileged(new PrivilegedAction<Object>() { 4 public Object run() { 5 invokeAwareMethods(beanName, bean); 6 return null; 7 } 8 }, getAccessControlContext()); 9 } 10 else { 11 invokeAwareMethods(beanName, bean); 12 } 13 14 Object wrappedBean = bean; 15 if (mbd == null || !mbd.isSynthetic()) { 16 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); 17 } 18 19 try { 20 invokeInitMethods(beanName, wrappedBean, mbd); 21 } 22 catch (Throwable ex) { 23 throw new BeanCreationException( 24 (mbd != null ? mbd.getResourceDescription() : null), 25 beanName, "Invocation of init method failed", ex); 26 } 27 28 if (mbd == null || !mbd.isSynthetic()) { 29 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); 30 } 31 return wrappedBean; 32 }
Look at the implementation of line 5 above:
1 private void invokeAwareMethods(final String beanName, final Object bean) { 2 if (bean instanceof BeanNameAware) { 3 ((BeanNameAware) bean).setBeanName(beanName); 4 } 5 if (bean instanceof BeanClassLoaderAware) { 6 ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader()); 7 } 8 if (bean instanceof BeanFactoryAware) { 9 ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this); 10 } 11 }
See here, if the bean is the implementation class of the BeanNameAware interface, the setBeanName method will be invoked, if the bean is the implementation class of the BeanClassLoaderAware interface, the setBeanClassLoader method will be invoked, and if it is the implementation class of the BeanFactoryAware interface, the setBeanFactory method will be invoked to inject the corresponding attribute values.
Calling BeanPostProcessor's postProcessBeforeInitialization method
The initializeBean method above looks at the implementation of 16 lines:
1 public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) 2 throws BeansException { 3 4 Object result = existingBean; 5 for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) { 6 result = beanProcessor.postProcessBeforeInitialization(result, beanName); 7 if (result == null) { 8 return result; 9 } 10 } 11 return result; 12 }
Traversing through the implementation of each BeanPostProcessor interface and calling the postProcessBeforeInitialization method, the timing of this interface call will be summarized. Here's a brief mention of the code.
Initialization method invoked
In 20 lines of initializeBean method, call the initialization method of Bean and see the implementation:
1 protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd) 2 throws Throwable { 3 4 boolean isInitializingBean = (bean instanceof InitializingBean); 5 if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { 6 if (logger.isDebugEnabled()) { 7 logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); 8 } 9 if (System.getSecurityManager() != null) { 10 try { 11 AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { 12 public Object run() throws Exception { 13 ((InitializingBean) bean).afterPropertiesSet(); 14 return null; 15 } 16 }, getAccessControlContext()); 17 } 18 catch (PrivilegedActionException pae) { 19 throw pae.getException(); 20 } 21 } 22 else { 23 ((InitializingBean) bean).afterPropertiesSet(); 24 } 25 } 26 27 if (mbd != null) { 28 String initMethodName = mbd.getInitMethodName(); 29 if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && 30 !mbd.isExternallyManagedInitMethod(initMethodName)) { 31 invokeCustomInitMethod(beanName, bean, mbd); 32 } 33 } 34 }
See, the code does two things:
1. Judge whether the Bean is an implementation class of InitializingBean. If so, turn the Bean strongly into InitializingBean and call the afterPropertiesSet() method directly.
2. Try to get init-method, if any, by reflection, call initMethod
Therefore, the two methods have their own advantages and disadvantages: the way to implement the Initializing Bean interface is more efficient, because the init-method method method is invoked through reflection; from another point of view, the coupling degree between the init-method method method and Spring will be lower. Which way to call the initialization method depends on personal preferences.
Calling BeanPostProcessor's postProcessAfterInitialization method
Finally, line 29 of the initializeBean method:
1 public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) 2 throws BeansException { 3 4 Object result = existingBean; 5 for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) { 6 result = beanProcessor.postProcessAfterInitialization(result, beanName); 7 if (result == null) { 8 return result; 9 } 10 } 11 return result; 12 }
Also traverse the BeanPostProcessor and call the postProcessAfterInitialization method. So we summarize the BeanPostProcessor method:
1. The BeanPostProcessor method of each configuration is invoked when initializing each Bean.
2. Call the postProcessBeforeInitialization method after the Bean property settings and Aware settings
3. Call the postProcessAfterInitialization method after the initialization method call
Registering Bean s that Need to Execute Destruction Methods
Next, take a look at line 83 of the top doCreateBean method, registerDisposable Bean IfNecessary (beanName, beans, mbd), and complete the last thing you need to do to create beans: register beans that need to execute the destruction method.
Look at the implementation of the following method:
1 protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) { 2 AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null); 3 if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) { 4 if (mbd.isSingleton()) { 5 // Register a DisposableBean implementation that performs all destruction 6 // work for the given bean: DestructionAwareBeanPostProcessors, 7 // DisposableBean interface, custom destroy method. 8 registerDisposableBean(beanName, 9 new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc)); 10 } 11 else { 12 // A bean with a custom scope... 13 Scope scope = this.scopes.get(mbd.getScope()); 14 if (scope == null) { 15 throw new IllegalStateException("No Scope registered for scope '" + mbd.getScope() + "'"); 16 } 17 scope.registerDestructionCallback(beanName, 18 new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc)); 19 } 20 } 21 }
In line 3, the first judgement is that it must not be prototype, and the second judgement is that the requiresDestruction method is implemented as follows:
1 protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) { 2 return (bean != null && 3 (bean instanceof DisposableBean || mbd.getDestroyMethodName() != null || 4 hasDestructionAwareBeanPostProcessors())); 5 }
To register a destruction method, a Bean needs to satisfy at least one of the following three conditions:
(1) Bean is the implementation class of Disposable Bean, at which point the interface method destroy() of Disposable Bean is executed.
(2) The destroy-method attribute is configured in the Bean tag, at which point the destroy-method configuration specified method is executed.
(3) The implementation class of the Destruction AwareBeanPostProcessor interface is held in the BeanFactory corresponding to the current Bean, at which time the interface method postProcessBeforeDestruction of the Destruction AwareBeanPostProcessor is executed
When one of the above three conditions is satisfied, the container registers to destroy the bean. The method of registering the bean is simple. See the registerDisposable Bean method for implementation.
1 public void registerDisposableBean(String beanName, DisposableBean bean) { 2 synchronized (this.disposableBeans) { 3 this.disposableBeans.put(beanName, bean); 4 } 5 }
When the container is destroyed, disposableBeans are traversed to execute the destruction method one by one.
Process summary
This article and the previous article analyzed the steps of Spring Bean initialization, and finally summarized the process of Spring Bean initialization with a graph:
Graph just plays the role of combing the process, throwing a brick to attract jade, the specific code implementation also requires netizens and friends to analyze step by step according to the code themselves.