From: juejin. Cn/post / 684490…

An overview of the

The core idea of Spring is the container. When the entire container is refreshed, the outside looks calm, but the inside is actually a sea. In addition, the whole process strictly abided by the open and closed principle, the internal closed to modify, open to expansion.

Think of the Spring container as a key ring filled with keys, each key as an extension interface. The order of keys is fixed, which can be understood as the order of interface calls is fixed, closed for modification. Each key can be used to do different things, understood as a different implementation of the extension interface, open to extension.

Spring provides a variety of rich extension interfaces. This article mainly focuses on the IOC process involved in the extension interface.

The corresponding UML is as follows:

The order of invocation is as follows:

Let’s look at them separately.

1. BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry

BeanDefinitionRegistryPostProcessor interface beanDefinition in a reading project after the execution, provides a complementary extension interface, used to dynamically register beanDefinition. Call a point: in PostProcessorRegistrationDelegate:

if (beanFactory instanceof BeanDefinitionRegistry) {
			//......
			// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
			boolean reiterate = true;
			while (reiterate) {
				reiterate = false; / / get all BeanDefinitionRegistryPostProcessor type of bean postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class,true.false);
				for (String ppName : postProcessorNames) {
					if(! ProcessedBeans. The contains (ppName)) {/ / by getBean method to instantiate currentRegistryProcessors. Add (the beanFactory) getBean (ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); reiterate =true; } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); currentRegistryProcessors.clear(); } / /... } Duplicate codeCopy the code

Example: Manually register BeanDefinition: :

@Component public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor { @Override  public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { System.out.println("postProcessBeanDefinitionRegistry ..."); / / register manually beanDefinition registry. RegisterBeanDefinition ("myBeanDefinitionRegistrar",new AnnotatedGenericBeanDefinition(MyBeanDefinitionRegistrar.class)); }} Copy the codeCopy the code

2 。BeanFactoryPostProcessor.postProcessBeanFactory

BeanFactoryPostProcessor interface is similar to BeanPostProcessor interface. The former interface has a factory, so this interface is the extension interface of beanFactory. After reading all the beanDefinition information and before instantiation, this interface can be used for further processing, such as modifying the beanDefinition, etc. Call point above the first extension interface, also in PostProcessorRegistrationDelegate:

if(beanFactory instanceof BeanDefinitionRegistry) { //...... // Do not initialize FactoryBeans here: We need to leave all regular beans // Get all BeanFactoryPostProcessor types String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class,true.false);

		// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
		// Ordered, and the rest.
		List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
		List<String> orderedPostProcessorNames = new ArrayList<>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
		for (String ppName : postProcessorNames) {
			if (processedBeans.contains(ppName)) {
				// skip - already processed in first phase above
			}
			else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
			}
			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
				orderedPostProcessorNames.add(ppName);
			}
			else{ nonOrderedPostProcessorNames.add(ppName); } } // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered. sortPostProcessors(priorityOrderedPostProcessors, beanFactory); / / perform all spring BeanFactoryPostProcessor implementation logic invokeBeanFactoryPostProcessors (priorityOrderedPostProcessors, the beanFactory); / /... } Duplicate codeCopy the code

Example: Dynamically modifying BeanDefinition:

@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        BeanDefinition myBeanDefinitionRegistrar = beanFactory.getBeanDefinition("myBeanDefinitionRegistrar"); // You can modify the beanDefinition information. Here sets the bean to singleton myBeanDefinitionRegistrar. SetScope (BeanDefinition. SCOPE_SINGLETON); }} Copy the codeCopy the code

3. InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation

Instantiation means Initialization or Initialization. PostProcessBeforeInstantiation used to retrieve the bean, if get, will no longer perform corresponding beans before initialization process, direct execution later speak postProcessAfterInitialization method. Call point in AbstractAutowireCapableBeanFactory:

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { //...... Try {/ / the method Object instantiated before 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); } / /... } Duplicate codeCopy the code
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
		Object bean = null;
		if(! Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) { // Make sure bean class is actually resolved at this point.if(! mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { Class<? > targetType = determineTargetType(beanName, mbd);if(targetType ! = null) {/ / perform bean = applyBeanPostProcessorsBeforeInstantiation postProcessBeforeInstantiation method (targetType, beanName); // If the result is not null, execute the instantiated extension interface directly. End the bean instantiation process.if(bean ! = null) { bean = applyBeanPostProcessorsAfterInitialization(bean, beanName); } } } mbd.beforeInstantiationResolved = (bean ! = null); }returnbean; } Duplicate codeCopy the code

If postProcessBeforeInstantiation get results is not null, then the end bean instantiation process.

4. SmartInstantiationAwareBeanPostProcessor.determineCandidateConstructors

This extension point determines the appropriate bean constructor. Specific reference AutowiredAnnotationBeanPostProcessor implementation class, for the following usage scenarios: through the constructor injection in MyComponent1 MyComponent2:

@Autowired
    public MyComponent(MyComponent2 component2){
        System.out.println("myComponent init..."); } Duplicate codeCopy the code

The appropriate constructor is selected and the required parameter bean is instantiated. Call point in AbstractAutowireCapableBeanFactory:

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { //...... // Get the appropriate constructor, if null, go to the default constructor. Constructor<? >[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);if(ctors ! = null || mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() | |! Objectutils.isempty (args)) {// If you find a constructor that references a dependency injection annotation, such as @autowired, call the autowireConstructor method for injectionreturn autowireConstructor(beanName, mbd, ctors, args);
		}

		// No special handling: simply use no-arg constructor.
		returninstantiateBean(beanName, mbd); } Duplicate codeCopy the code

5. MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition

This interface is used to merge beanDefinitions and is also an extension interface to beanDefinitions. The most common usage scenarios: AutowiredAnnotationBeanPostProcessor implementation class, through the interface parsing all specified in the current bean annotation types of properties:

this.autowiredAnnotationTypes.add(Autowired.class); this.autowiredAnnotationTypes.add(Value.class); Copy the codeCopy the code

By default, the attributes of the last two annotations are parsed and their descriptions are merged into the beanDefinition of the current object, which is then retrieved and injected during the property populateBean filling process. Call point in AbstractAutowireCapableBeanFactory:

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

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if(mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } // instantiate the beanif(instanceWrapper == null) { instanceWrapper = createBeanInstance(beanName, mbd, args); } final Object bean = instanceWrapper.getWrappedInstance(); Class<? > beanType = instanceWrapper.getWrappedClass();if(beanType ! = NullBean.class) { mbd.resolvedTargetType = beanType; } // Allow post-processors to modify the merged bean definition. synchronized (mbd.postProcessingLock) {if(! MBD. PostProcessed) {try {/ / perform postProcessMergedBeanDefinition logic applyMergedBeanDefinitionPostProcessors (MBD, beanType, beanName); } catch (Throwable ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true; }} / /...returnexposedObject; } Duplicate codeCopy the code

6. InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation

Instantiated the method called, in AbstractAutowireCapableBeanFactory populateBean () will trigger in the filling method. This method returns true by default, and if false is returned, the populateBean method is broken, that is, the property injection process is no longer performed. In real projects, this extension method is rarely used.

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
		// ......
		boolean continueWithPropertyPopulation = true;

		if(! mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					if(! ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {continueWithPropertyPopulation = false;
						break; }}}}if (!continueWithPropertyPopulation) {
			return; } / /... } Duplicate codeCopy the code

7. SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference

The getEarlyBeanReference method is called whenever Spring has a loop dependency. First, when the bean is created, callback methods are exposed ahead of time for post-processing of bean instantiation to prevent subsequent loop dependencies. The getEarlyBeanReference method is fired in the exposed callback method.

Specific call point in DefaultSingletonBeanRegistry:

@Nullable protected Object getSingleton(String beanName, boolean allowEarlyReference) { Object singletonObject = this.singletonObjects.get(beanName); // If the bean has not been instantiated and is being created.if(singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { // Determine whether the bean reference has been exposed ahead of time. singletonObject = this.earlySingletonObjects.get(beanName); // If you run a loop dependencyif(singletonObject == null && allowEarlyReference) { ObjectFactory<? > singletonFactory = this.singletonFactories.get(beanName);if(singletonFactory ! = null) {/ / call the getObject () method singletonObject = singletonFactory. GetObject (); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); }}}}returnsingletonObject; } Duplicate codeCopy the code

Call the getEarlyBeanReference method in getObject() to complete the bean initialization process.

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
		Object exposedObject = bean;
		if(! mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if(bp instanceof SmartInstantiationAwareBeanPostProcessor) { SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp; exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName); }}}returnexposedObject; } Duplicate codeCopy the code

General process:

When A is instantiated, Spring IOC populates the attributes that A depends on, and if A is found to be dependent on B, B is instantiated. Similarly, when populating B’s properties, if B also references A, A cyclic dependency occurs. Because A has not yet been created and injected into Spring.

Spring does this by triggering a callback function on the cache being created, similar to a buried point operation, to end the bean’s initialization if a loop dependency occurs during the subsequent fill property phase.

When A is instantiated, A callback method, ObjectFactory (changed to A functional interface in Spring5), is exposed in the cache ahead of time. When B references A and finds that A has not yet been instantiated, the initialization of A is completed through the callback method in the cache, and THEN B is injected. It then continues the process of populating the properties of A, injecting B into A, and terminating the circular dependency.

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, () -> getEarlyBeanReference(beanName, MBD, bean)); } try {// Fill the property where the loop dependency occurs populateBean(beanName, MBD, instanceWrapper); 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); }} / /... Copy the codeCopy the code

8. InstantiationAwareBeanPostProcessor.postProcessPropertyValues

This method is used for property injection and is triggered during property population during bean initialization. Annotation principles such as @autowired and @Resource are realized based on this method. Specific method in AbstractAutowireCapableBeanFactory populateBean call points:

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
		//......
	if (hasInstAwareBpps || needsDepCheck) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
			PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
			if (hasInstAwareBpps) {
				for (BeanPostProcessor bp : getBeanPostProcessors()) {
					if(bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; / / get all the implementation class of the PVS = ibp. PostProcessPropertyValues (PVS, filteredPds, bw. GetWrappedInstance (), beanName);if (pvs == null) {
							return; }}}}if(needsDepCheck) { checkDependencies(beanName, mbd, filteredPds, pvs); }} / /... } Duplicate codeCopy the code

The realization of the above methods can obtain all postProcessPropertyValues method. For example: in AutowiredAnnotationBeanPostProcessor is implemented as follows, also is the implementation code of dependency injection:

@Override
	public PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {

		InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
		try {
			metadata.inject(bean, beanName, pvs);
		}
		catch (BeanCreationException ex) {
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
		}
		returnpvs; } Duplicate codeCopy the code

9. ApplicationContextAwareProcessor.invokeAwareInterfaces

This extension point is used to execute various driver interfaces. After the bean is instantiated and the property is populated, the following driver interface is implemented via the extension interface:

private void invokeAwareInterfaces(Object bean) {
		if (bean instanceof Aware) {
			if(bean instanceof EnvironmentAware) { ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());  }if (bean instanceof EmbeddedValueResolverAware) {
				((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
			}
			if (bean instanceof ResourceLoaderAware) {
				((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
			}
			if (bean instanceof ApplicationEventPublisherAware) {
				((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
			}
			if (bean instanceof MessageSourceAware) {
				((MessageSourceAware) bean).setMessageSource(this.applicationContext);
			}
			if(bean instanceof ApplicationContextAware) { ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext); }}} copy the codeCopy the code

Therefore, you only need to implement the above six driver interfaces to obtain the corresponding container-related variables. These variables are more commonly used in real projects.

Usage:

@Component public class MyComponent implements ApplicationContextAware, InitializingBean, BeanClassLoaderAware ,ResourceLoaderAware,EnvironmentAware { @Override public void afterPropertiesSet() throws Exception  { System.out.println("afterPropertiesSet init...");
    }
    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        System.out.println("setBeanClassLoader init...");
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

        System.out.println("setApplicationContext init...");
    }
    @Override
    public void setEnvironment(Environment environment) {

        System.out.println("setEnvironment init...");
    }
    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        System.out.println("setResourceLoader init..."); }} Copy the codeCopy the code

10. BeanFactoryPostProcessor.postProcessBeforeInitialization

The two extension interfaces in BeanFactoryPostProcessor are the last two extension interfaces in the Spring IOC process. Including postProcessBeforeInitialization used in bean instantiation, the afterPropertiesSet method is performed before the front interface. The setting-driven method invokeAwareInterfaces above implements this interface for setting some properties on the bean. The call point is as follows:

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		if(System.getSecurityManager() ! = null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { invokeAwareMethods(beanName, bean);return null;
			}, getAccessControlContext());
		}
		else {
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if(mbd == null || ! MBD. IsSynthetic ()) {/ / execution front extension methods wrappedBean = applyBeanPostProcessorsBeforeInitialization (wrappedBean, beanName); } try {afterPropertiesSet invokeInitMethods(beanName, wrappedBean, MBD); } catch (Throwable ex) { throw new BeanCreationException( (mbd ! = null ? mbd.getResourceDescription() : null), beanName,"Invocation of init method failed", ex);
		}
		if(mbd == null || ! MBD. IsSynthetic ()) {/ / execution rear extension methods wrappedBean = applyBeanPostProcessorsAfterInitialization (wrappedBean, beanName); }returnwrappedBean; } Duplicate codeCopy the code

11. InitializingBean.afterPropertiesSet

Method used to set properties after bean is instantiated. As mentioned above, this method call is triggered in the invokeInitMethods method:

protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
			throws Throwable {
		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 {/ / execution afterPropertiesSet AccessController. The doPrivileged ((PrivilegedExceptionAction < Object >) () - > { ((InitializingBean) bean).afterPropertiesSet();returnnull; }, getAccessControlContext()); } catch (PrivilegedActionException pae) { throw pae.getException(); }}else{// Execute afterPropertiesSet((InitializingBean) bean).afterPropertiesSet(); }}} copy the codeCopy the code

12. BeanFactoryPostProcessor.postProcessAfterInitialization

This method is the last commonly used extension point in the Spring IOC process for post-processing after bean initialization. At this point in the IOC process, a complete bean has been created and can be wrapped or propped up. The Spring AOP principle is based on this extension point and is implemented in Abstractauto XyCreator:

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
		if(bean ! = null) { Object cacheKey = getCacheKey(bean.getClass(), beanName);if(! this.earlyProxyReferences.contains(cacheKey)) {returnwrapIfNecessary(bean, beanName, cacheKey); }}returnbean; } Duplicate codeCopy the code

Interested to Spring AOP related articles: SpringBoot2 | Spring AOP principle source depth profiling (8)

The specific usage method has been uploaded to github: github.com/admin801122…

conclusion

When we use Spring or SpringBoot, we can easily implement some extension and enhancement of the logic in the Spring IOC process through the above reserved extension interface of Spring. Like the Servlet specification, it can be understood as interface oriented programming.