Previous posts:

1. Deep understanding of Spring IOC(I), unified resource loading

2. Deep understanding of Spring IOC(ii), from XML to BeanDefinition

3, In-depth understanding of Spring IOC(iii), refresh method before instantiation preparations

4. Deep understanding of Spring IOC

5. Create a bean instance

If you’ve seen this and you’ve seen everything before, congratulations, you’ve got the hard part covered. It should not be too difficult for you to go through the whole Spring IOC process now, and it should be relatively easy to look at the source code of other Spring modules, especially other framework and Spring integration code. If you do not understand also don’t worry, you can finish reading this, and then go back to see before, the source code is very few people can see it, I see this piece of source code is also read a lot of times and debug a lot of times to understand.

Really need you a praise to encourage, because write this kind of source code analysis really Mrs. Mrs. Is not easy 😢, who writes who knows.Copy the code

The createBeaninstance method in doCreateBean creates an unpopulated bean instance for us. In this article, we will look at how the created bean instance is populated and initialized.

Let’s go back to the doCreateBean method, and I’ll post the code for that method again, as I did in part 1, and let’s go straight to part 2

Protected Object doCreateBean(Final String beanName, Final RootBeanDefinition MBD, BeanWrapper instanceWrapper = null; // BeanWrapper instanceWrapper = null; If (mbd.issingleton ()) {// Remove the factoryBean from the cache that you are creating. At the same time removing) instanceWrapper = this. FactoryBeanInstanceCache. Remove (beanName); } if (instanceWrapper == null) { // 1. InstanceWrapper = createBeanInstance(beanName, MBD, args); } final Object bean = (instanceWrapper ! = null ? instanceWrapper.getWrappedInstance() : null); Class<? > beanType = (instanceWrapper ! = null ? instanceWrapper.getWrappedClass() : null); / / use MergedBeanDefinitionPostProcessor modify RootBeanDefinition / / mainly deal with @autowired, @ inject, @ the value standard of the methods and properties / / back from here, Spring only knows which method or property has this annotation. // The specific code parsing here is not posted (because it is not important). You can also download the source code for my first post on Github. Synchronized (mbd.postProcessingLock) {if (! mbd.postProcessed) { applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); mbd.postProcessed = true; } // earlySingletonExposure is used to determine whether to expose the semi-finished product in advance. The current bean is a work-in-progress because it has not yet been populated with properties, // MBD is a singleton && allows circular references (default true) && Whether the current bean is being created 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"); } // Expose the beanName corresponding ObjectFactory in advance, AddSingletonFactory (beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { // 2. When using SmartInstantiationAwareBeanPostProcessor return early bean semi-finished products of reference / / if there is no SmartInstantiationAwareBeanPostProcessor, Return getEarlyBeanReference(beanName, MBD, bean); }}); } // Initialize Object exposedObject = bean; Try {// 3. Fill the bean with properties populateBean(beanName, MBD, instanceWrapper); if (exposedObject ! = null) {// 4. Initialize 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) {// due to the operation after init, earlySingletonReference and exposedObject may not bean instance, // We need them to point to an instance, exposedObject = earlySingletonReference; }else if (! Enclosing allowRawInjectionDespiteWrapping && hasDependentBean (beanName)) {/ / get the current bean rely on all String bean array [] dependentBeans = getDependentBeans(beanName); Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length); For (String dependentBean: dependentBeans) {// Remove the bean because the bean depends on the enhanced bean if (! RemoveSingletonIfCreatedForTypeCheckOnly (dependentBean)) {/ / remove added to actualDependentBeans failure 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."); Try {}}}} / / registered for the destruction of the bean, registerDisposableBeanIfNecessary (beanName, bean, MBD); }catch (BeanDefinitionValidationException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); } return exposedObject; }Copy the code

2 in block 1

Protected Object getEarlyBeanReference(String beanName, RootBeanDefinition MBD, Object bean) { Object exposedObject = bean; / / bean is not null & & MBD synthetic && have InstantiationAwareBeanPostProcessor if (bean! = null && ! MBD. IsSynthetic () && hasInstantiationAwareBeanPostProcessors ()) {/ / traversal BeanPostProcessor for (BeanPostProcessor bp: getBeanPostProcessors()) { if (bp instanceof SmartInstantiationAwareBeanPostProcessor) { SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp; / / specific processing logic in AutowiredAnnotationBeanPostProcessor, it inherited this method, finally is returned or bean itself, / / note: If there are other implements SmartInstantiationAwareBeanPostProcessor is not necessarily exposedObject = ibp. GetEarlyBeanReference (exposedObject, beanName);  if (exposedObject == null) { return exposedObject; } } } } return exposedObject; }Copy the code

Now I’m sure you can see this

3 in block 1

This populateBean method, which handles property injection, @autowired, @Resource, @Value, and even @Reference when you use the Dubbo framework, handles injection here. Let’s take a look at this method:

Protected void populateBean(String beanName, RootBeanDefinition MBD, BeanWrapper bw) { PropertyValues pvs = mbd.getPropertyValues(); If (bw == null) {// If (bw == null) { pvs.isEmpty()) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance"); }else {return; }} / / whether or not to continue filling properties of tag Boolean continueWithPropertyPopulation = true; / / MBD is synthetic && exists InstantiationAwareBeanPostProcessor if (! mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; / / postProcessAfterInstantiation this approach after the bean is instantiated attribute fill before call / / return is true, that should be fill, false description should not be an if (! ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { continueWithPropertyPopulation = false; break; }}}} // Return if (! continueWithPropertyPopulation) { return; } autowire (byname, byType) {autowire (byname, byType); No byName annotations and byType attribute the if (MBD) getResolvedAutowireMode () = = RootBeanDefinition. AUTOWIRE_BY_NAME | | mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { MutablePropertyValues newPvs = new MutablePropertyValues(pvs); / / 1. The byName of processing the if (MBD) getResolvedAutowireMode () = = RootBeanDefinition. AUTOWIRE_BY_NAME) {autowireByName (beanName, mbd, bw, newPvs); } / / 2. ByType processing the if (MBD) getResolvedAutowireMode () = = RootBeanDefinition. AUTOWIRE_BY_TYPE) {autowireByType (beanName, mbd, bw, newPvs); } pvs = newPvs; } / / is there a InstantiationAwareBeanPostProcessors Boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors (); Boolean needsDepCheck = (mbd.getDependencyCheck()! = RootBeanDefinition.DEPENDENCY_CHECK_NONE); if (hasInstAwareBpps || needsDepCheck) { PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); if (hasInstAwareBpps) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { // Use InstantiationAwareBeanPostProcessor post processing for filling / / here is attribute to fill in the last step before treatment, @autoWired is where the @autowired attribute is initialized and added to the PVS. @Resource is also where the BeanPostProcessor is used. The @autowired processing logic in AutowiredAnnotationBeanPostProcessor, And / / @ Resource in CommonAnnotationBeanPostProcessor InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvs == null) { return; }}}} if (needsDepCheck) {checkDependencies(beanName, MBD, filteredPds); } // 3. ApplyPropertyValues (beanName, MBD, bw, PVS); }Copy the code

One or two of these code blocks are for the autowire attribute of the bean tag in XML, which is rarely used now, but for the sake of completeness, let’s look at it:

1 in block 3

Protected void autowireByName(String beanName, AbstractBeanDefinition MBD, BeanWrapper BW, MutablePropertyValues PVS) {/ / get the name of the attribute need to inject a String [] the putobject = unsatisfiedNonSimpleProperties (MBD, bw); for (String propertyName : // beanDefinition if (containsBean(propertyName)) {// beanDefinition if (containsBean(propertyName)) { Object bean = getBean(propertyName); // Add the dependent bean to the PVS container for later use of pvs.add(propertyName, bean); RegisterDependentBean (propertyName, beanName); if (logger.isDebugEnabled()) { logger.debug("Added autowiring by name from bean name '" + beanName + "' via property '" + propertyName + "' to bean named '" + propertyName + "'"); } } else { if (logger.isTraceEnabled()) { logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName + "' by name: no matching bean found"); }}}}Copy the code

2 in block 3

Protected void autowireByType(String beanName, AbstractBeanDefinition MBD, BeanWrapper BW, MutablePropertyValues PVS) {// Take custom TypeConverter, if null, TypeConverter Converter = getCustomTypeConverter(); if (converter == null) { converter = bw; } Set<String> autowiredBeanNames = new LinkedHashSet<String>(4); / / get a need to inject the name of the attribute String [] the putobject = unsatisfiedNonSimpleProperties (MBD, bw); for (String propertyName : PropertyNames) {try {// Get bw corresponding to the propertyName descriptor PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName); // If pd is of type Object, this is not injected. The reason for this is that if it is Object, the argument you find will be injected even if the type does not match //. if (! Object.class.equals(pd.getPropertyType())) { MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd); // Do not allow eager init for type matching in case of a prioritized post-processor. boolean eager = ! PriorityOrdered.class.isAssignableFrom(bw.getWrappedClass()); DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager); ResolveDependency (desc, beanName, autowiredBeanNames, Converter); // Put the parsed parameters into PVS if (autowiredArgument! = null) { pvs.add(propertyName, autowiredArgument); } for (String autowiredBeanName : autowiredBeanNames) { registerDependentBean(autowiredBeanName, beanName); if (logger.isDebugEnabled()) { logger.debug("Autowiring by type from bean name '" + beanName + "' via property '" + propertyName + "' to bean named '" + autowiredBeanName + "'"); } } autowiredBeanNames.clear(); } } catch (BeansException ex) { throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex); }}}Copy the code

3 in block 3

By 3.3, Spring already knows which property of the bean needs to be injected and has the injected value. Let’s look at the code here:

Protected void applyPropertyValues(String beanName, BeanDefinition MBD, BeanWrapper BW, PropertyValues PVS) {/ / if the PVS for empty return directly if (PVS = = null | | PVS. IsEmpty () {return; } MutablePropertyValues mpvs = null; List<PropertyValue> original; if (System.getSecurityManager() ! = null) { if (bw instanceof BeanWrapperImpl) { ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext()); } } if (pvs instanceof MutablePropertyValues) { mpvs = (MutablePropertyValues) pvs; // If the MPVS attribute value has been converted to the corresponding type, In line with PHP, you can just set if (mpv.is.php ()) {try {// in line with what you can do with BeanWrapper Since BeanWrapper implements PropertyAccessor, you can give a set value directly to // if you are interested, you can explore bw.setPropertyValues(MPVS); return; }catch (BeansException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Error setting property values", ex); } } original = mpvs.getPropertyValueList(); }else {// Get the original properties original = arrays.asList (pvs.getpropertyValues ()); } TypeConverter converter = getCustomTypeConverter(); if (converter == null) { converter = bw; } / / get the parser BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver (this, beanName, MBD, the converter); // Make a deep copy of the original attributes, // DeepCopy is a List<PropertyValue> deepCopy = new that is used directly to fill the bean with properties ArrayList<PropertyValue>(original.size()); boolean resolveNecessary = false; For (PropertyValue pv: original) {for (PropertyValue pv: original) {// if a property isConverted then just add deepCopy if (pv.isconverted ()) {deepCopy. Add (pv); }else {String propertyName = pv.getName();}else {String propertyName = pv.getName(); Object originalValue = pv.getValue(); / / and parsing, and make the necessary analytical Object resolvedValue = valueResolver. ResolveValueIfNecessary (pv, originalValue); Object convertedValue = resolvedValue; Boolean convertible = bw. IsWritableProperty (propertyName) &&! PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName); if (convertible) { convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter); } if (resolvedValue == originalValue) {if (convertible) {pv.setconvertedValue (convertedValue); } deepCopy.add(pv); }else if (convertible && originalValue instanceof TypedStringValue && ! ((TypedStringValue) originalValue).isDynamic() && ! (convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) { pv.setConvertedValue(convertedValue); deepCopy.add(pv); }else { resolveNecessary = true; deepCopy.add(new PropertyValue(pv, convertedValue)); }}} // set converted to true if (MPVS! = null && ! resolveNecessary) { mpvs.setConverted(); } // Try {bw. SetPropertyValues (new MutablePropertyValues(deepCopy)); }catch (BeansException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Error setting property values", ex); }}Copy the code

In this case, the BeanPostProcessor method is used to call the BeanPostProcessor method. In this case, the BeanPostProcessor method is called. Moving on to 1.4, this method is primarily for bean initialization.

4 in block 1

Protected Object initializeBean(Final String beanName, Final Object bean RootBeanDefinition MBD) {/ / call several Aware interface if (System. GetSecurityManager ()! = null) { AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { // 1. Call Aware invokeAwareMethods(beanName, bean); return null; } }, getAccessControlContext()); } else { invokeAwareMethods(beanName, bean); } / / 2. Call all the BeanPostProcessor postProcessBeforeInitialization Object wrappedBean = bean; if (mbd == null || ! mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try {// 3. Call the InitializingBean method and custom initialization method invokeInitMethods(beanName, wrappedBean, MBD); }catch (Throwable ex) { throw new BeanCreationException( (mbd ! = null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } / / 4. Perform all BeanPostProcessor postProcessAfterInitialization method if (MBD = = null | |! mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }Copy the code

The first step is to call the Aware interface. I will write an article about the Aware interface. We will first look at what this method does:

1 in block 7

Private void invokeAwareMethods(final String beanName, final Object bean) {// xxxAware, If (bean instanceof Aware) {// Set name if (bean instanceof BeanNameAware) {((BeanNameAware) bean).setBeanName(beanName); } // Class loader if (bean instanceof BeanClassLoaderAware) {((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader()); } // We sometimes use BeanFactoryAware to get BeanFactory, If (bean instanceof BeanFactoryAware) {((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this); }}}Copy the code

2 in block 7

Code block 9 public Object applyBeanPostProcessorsBeforeInitialization (Object existingBean, String beanName) throws BeansException { Object result = existingBean; / / call all the BeanPostProcessor postProcessBeforeInitialization / / (preposition) method One of @ PostConstruct is performed for CommonAnnotationBeanPostProcessor for (BeanPostProcessor beanProcessor: getBeanPostProcessors()) { result = beanProcessor.postProcessBeforeInitialization(result, beanName); if (result == null) { return result; } } return result; }Copy the code

3 in block 7

InitialBean InitialBean InitialBean InitialBean InitialBean InitialBean InitialBean InitialBean InitialBean

Protected void invokeInitMethods(String beanName, final Object bean, Throws Throwable {// Call the afterPropertiesSet method of InitializingBean, Boolean isInitializingBean = (Bean instanceof InitializingBean); if (isInitializingBean && (mbd == null || ! mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { if (logger.isDebugEnabled()) { logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); } if (System.getSecurityManager() ! = null) { try { AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { @Override public Object run() throws Exception { // ((InitializingBean) bean).afterPropertiesSet(); return null; } }, getAccessControlContext()); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else { ((InitializingBean) bean).afterPropertiesSet(); } } if (mbd ! = null) { String initMethodName = mbd.getInitMethodName(); if (initMethodName ! = null && ! (isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && ! MBD. IsExternallyManagedInitMethod (initMethodName)) {/ / calls a custom initialization method, InvokeCustomInitMethod (beanName, bean, MBD) is called primarily by reflection; }}}Copy the code

4 in block 7

This method is also the final step in initialization

The code block 11 public Object applyBeanPostProcessorsAfterInitialization (Object existingBean, String beanName) throws BeansException {/ / execute all the BeanPostProcessor postProcessAfterInitialization Object (rear) method result =  existingBean; // execute for (BeanPostProcessor beanProcessor: getBeanPostProcessors()) { result = beanProcessor.postProcessAfterInitialization(result, beanName); if (result == null) { return result; } } return result; }Copy the code

So far, we have covered the loading and parsing of beans in XML. In the next article, we will summarize the process and expand on some of the interview points to give you a better understanding of the whole bean loading process.