Before we did two BeanDefinition rear loading and the BeanFactory processor, mainly analyzes the registry and invokeBeanFactoryPostProcessors these two methods. Today we are going to look at two other important approaches. RegisterBeanPostProcessors and finishBeanFactoryInitialization. These methods are AnnotationConfigApplicationContext refresh method.

Register Bean post-processor

RegisterBeanPostProcessors method is responsible for the initialization implements the BeanPostProcessor interface of Bean, and register it into the BeanFactory.

Post processor BeanPostProcessor postProcessBeforeInitialization and postProcessAfterInitialization defines two methods. Spring adds all the beanPostProcessors to the BeanFactory list of beanPostProcessors.

BeanPostProcessor can be understood as a helper class, and during the initialization of all other types of beans (application beans), Before and after the Spring will respectively in their initial call postProcessBeforeInitialization and postProcessAfterInitialization BeanPostProcessor instance.

BeanFactoryPostProcessor is the same thing as BeanPostProcessor. After the BeanFactory is created, Spring calls the postProcessBeanFactory method of all Instances of BeanFactoryPostProcessor, giving the user the opportunity to extend the Bean after the BeanFactory is created.

Now look at registerBeanPostProcessors source code:

protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    	/ / call PostProcessorRegistrationDelegate registerBeanPostProcessors method
		PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
	}
Copy the code

See PostProcessorRegistrationDelegate registerBeanPostProcessors source code:

public static void registerBeanPostProcessors( ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
		// Get all postProcessor names
		String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true.false);

		
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
		for (String ppName : postProcessorNames) {
            / / in nonOrderedPostProcessorNames list, omitted here other code, are processing priority. BesnPostProcessor can also set the priority, the higher the priority will be called first.
            nonOrderedPostProcessorNames.add(ppName);
		}

		

		// Now, register all regular BeanPostProcessors.
		List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
		for (String ppName : nonOrderedPostProcessorNames) {
            // Instantiate the BeanPostProcessor instance
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			nonOrderedPostProcessors.add(pp);
		}
    
    	/ / register BestProcessor
		registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
	}
Copy the code

See registerBeanPostProcessors source code:

private static void registerBeanPostProcessors( ConfigurableListableBeanFactory beanFactory, List
       
         postProcessors)
        {

    	// Add all beanPostProcessors to beanFactory
		for(BeanPostProcessor postProcessor : postProcessors) { beanFactory.addBeanPostProcessor(postProcessor); }}Copy the code

The beanFactory is a DefaultListableBeanFactory object, let’s take a look at the code, very simple, almost is a line of code:

@Override
	public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {		
		// Remove from old position, if any
		this.beanPostProcessors.remove(beanPostProcessor);		
		// Add beanPostProcessor to the list of beanPostProcessors
		this.beanPostProcessors.add(beanPostProcessor);
	}
Copy the code

When you call the initializeBean method to create all the application beans, it polls the objects in beanPostProcessors, And before and after the Bean instantiation call postProcessBeforeInitialization and postProcessAfterInitialization method respectively.

The BeanPostProcessor registration process is relatively simple. It mainly describes its role in the Spring Bean initialization process. Next we see finishBeanFactoryInitialization one of most important method.

Initialize the Bean object

Refresh method in our last one way to tell is finishBeanFactoryInitialization, it is responsible for according to BeanDefinition create Bean object, and perform some related to Bean lifecycle callback function. Let’s look directly at the source code:

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
		/ / omit other handling code, calling the beanFactory preInstantiateSingletons directly.
		beanFactory.preInstantiateSingletons();
	}
Copy the code

Always remember the beanFactory is DefaultListableBeanFactory object, so look at its preInstantiateSingletons source code.

// The prototypebean is created every time getBean is called. It is not initialized when the container is started.
public void preInstantiateSingletons(a) throws BeansException {		
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);		
		for (String beanName : beanNames) {
            // The FactoryBean object handling logic is omitted. If it is isEglarBean, the getBean method is also called. So, no matter what sigleton bean is, the getBean method is called
			getBean(beanName);
		}

		/ / omit SmartInitializingSingleton processing, interested can go to understand the role of this class...
	}

public Object getBean(String name) throws BeansException {
    	// getBean calls the doGetBean method.
		return doGetBean(name, null.null.false);
	}
Copy the code

Take a look at the code for doGetBean. To reduce the content of the article, only the core code is posted:

final String beanName = transformedBeanName(name);
		Object bean;

		/ / take simple interest Bean, here a brief introduction of DefaultListableBeanFactory another integration relationship, it inherits the DefaultSingletonBeanRegistry class. This class allows simple management by defining a HashMap
      
       , maintaining the relationship between bean names and bean objects, and ensuring that only one bean Object is created for each bean name.
      ,object>
		Object sharedInstance = getSingleton(beanName);
		if(sharedInstance ! =null && args == null) {
            // If a bean exists in the cache (HashMap above), the bean is fetched
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

		else {
			// BeanFactory can be inherited. If the Bean definition is not found in the current BeanFactory, look for it in the parent BeanFactory.
			BeanFactory parentBeanFactory = getParentBeanFactory();
			if(parentBeanFactory ! =null && !containsBeanDefinition(beanName)) {
				// Not found -> check parent.
				String nameToLookup = originalBeanName(name);
                // Omit the parameter processing process. Go directly to the parent BeanFactory.
				return (T) parentBeanFactory.getBean(nameToLookup);
			}			

			try {
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				// Bean dependencies are handled first, and if the current Bean depends on another Bean, the dependent Bean is registered and instantiated first.
				String[] dependsOn = mbd.getDependsOn();
				if(dependsOn ! =null) {
					for (String dep : dependsOn) {
						// Register the dependent Bean first
						registerDependentBean(dep, beanName);
                        // Instantiate the dependent BeangetBean(dep); }}// Create bean instance.
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
                        // Create a simple interest Bean
                        return createBean(beanName, mbd, args);
						
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}

				else if (mbd.isPrototype()) {
					// Prototyp beans are created each time.
					Object prototypeInstance = null;
					try {
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						afterPrototypeCreation(beanName);
					}
					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}

				else {
					// To handle other types of beans, such as extended types Session, Request, etc., the code omitted..}}catch (BeansException ex) {
				cleanupAfterBeanCreationFailure(beanName);
				throwex; }}// The type conversion code is also omitted...
		return (T) bean;


Copy the code

Take a look at what createBean does.

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args){	
    	// The rest of the code is omitted, except that the doCreateBean method is called
		Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    	return beanInstance;
	}
Copy the code

Look at the doCreateBean code:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {

		/ / create the BeanWrapper.
		BeanWrapper instanceWrapper = null;		
		if (instanceWrapper == null) {
            // Call createBeanInstance to create an instance of the Bean. This method will not be read in detail. The general idea is to find the classType based on RootBeanDefinition and get its constructor. We then use reflection to dynamically create a bean instance from the constructor, wrap the instance, and return the BeanWrapper object. It is also possible to create beans dynamically using CGLib when bean enhancements are required, but we will cover only the simplest case here.
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final Object bean = instanceWrapper.getWrappedInstance();		

		
		Object exposedObject = bean;
		try {
            // Assign the bean property according to the BeanDefinition.
            populateBean(beanName, mbd, instanceWrapper);
            // Initialize the Bean, where the Bean lifecycle callbacks are executed, such as setting beanName, calling postBestProcessor, etc.
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {			
		}

		return exposedObject;
	}
Copy the code

The two important methods above are createBeanInstance and initializeBean. What createBeanInstance does is basically find its classType based on RootBeanDefinition, get its constructor, and then use reflection to dynamically create an instance of the bean from that constructor, wrap that instance, Return the BeanWrapper object. Because the business of this class is simple and most of the code deals with reflection, we won’t analyze it anymore. Let’s focus on the initializeBean method.

Take a look at the initializeBean code:

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		Spring provides a large number of *Aware interfaces for setting values to beans, such as injecting ApplicationContext, ClassLoader, etc.
    	invokeAwareMethods(beanName, bean);

		Object wrappedBean = bean;
		if (mbd == null| |! mbd.isSynthetic()) {/ / if the Bean implements the BeanPostProcessor interface, perform postProcessBeforeInitialization method.
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
            // Execute bean initialization related methods. If the bean implements the InitializingBean interface, its afterPropertiesSet method is called. If the bean specifies a user-defined init-method method, the custom method is also executed.
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw newBeanCreationException( (mbd ! =null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		if (mbd == null| |! mbd.isSynthetic()) {/ / if the Bean implements the BeanPostProcessor interface, perform postProcessAfterInitialization method.
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}
Copy the code

The implementation of the interface methods in the above code is straightforward: determine whether the Bean object implements an interface and, if it does, invoke the methods defined by the interface. InitializeBean is an important method that involves the life cycle of the Bean and is a common interview topic. It is also important, and we can do a lot of things during Bean initialization.

So far, the Bean initialization is finished, from finishBeanFactoryInitialization – > getBean – > createBean – > initializeBean. The bean is initialized and the relevant callback methods in the bean life cycle are executed.

conclusion

Today we looked at registering bean post-handlers and loading beans.

Spring defines the BeanPostProcessor interface, and all beans that implement this interface are registered with Spring’s list of post-processors. Post-handlers are analogous to helper classes, all of which are invoked by application beans after they are initialized. This gives the user the opportunity to modify or extend the bean before and after initialization.

Then we looked at the most important bean loading. The ApplicationContext loads all non-Lazi-init Singleton beans when the container is started. ApplicationContext implements the BeanDefinitionRegistry interface and has previously registered all BeanDefination and stored it ina HashMap. When the bean is loaded, all beanDefinitions are read from the HashMap and their getBean methods are called. GetBean is meant to get the bean, but if not, it is created and initialized.

The doGetBean method is called to get the bean, first checking to see if the current bean is defined, and then looking it up in the parent BeanFactory. It also checks whether the current bean is dependent on other beans, and if so, creates the dependent bean first.

Creating a bean is done by taking its constructor from the classType in BeanDefinition, using reflection to create an instance of the bean, and then calling the populateBean method to set the properties, Finally, call initializeBean to call back some interface methods related to the bean life cycle.

At this point, the entire Spring container is started.


All posts are synced on Github, and you can also visit my personal blog