spring source code analysis - beanfactoryprocessor

Posted by mediabob on Mon, 03 Jan 2022 14:10:05 +0100

spring series

preface

Beanfactoryprocessor is not only a hook interface of BeanFactory, but also an extension. It is precisely because of this interface that spring loads beans in a variety of ways. I believe most developers may be unfamiliar with this interface. After all, this interface belongs to an underlying extension. If you are a spring plug-in developer, you must be familiar with this interface. This article analyzes how spring loads beans through Bean definition registry postprocessor from the perspective of source code.

Introduction to beanfactoryprocessor

We check the hierarchy of beanfactoryprocessor from the source code and find that it also has a sub interface BeanDefinitionRegistryPostProcessor. The code structure is as follows:

BeanFactoryPostProcessor

@FunctionalInterface
public interface BeanFactoryPostProcessor {

	/**
	 * Modify the application context's internal bean factory after its standard
	 * initialization. All bean definitions will have been loaded, but no beans
	 * will have been instantiated yet. This allows for overriding or adding
	 * properties even to eager-initializing beans.
	 * @param beanFactory the bean factory used by the application context
	 * @throws org.springframework.beans.BeansException in case of errors
	 */
	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

According to the source code, we know that there is only one method postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory). We use this BeanFactory to enhance the function of BeanFactory.

BeanDefinitionRegistryPostProcessor

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {

	/**
	 * Modify the application context's internal bean definition registry after its
	 * standard initialization. All regular bean definitions will have been loaded,
	 * but no beans will have been instantiated yet. This allows for adding further
	 * bean definitions before the next post-processing phase kicks in.
	 * @param registry the bean definition registry used by the application context
	 * @throws org.springframework.beans.BeansException in case of errors
	 */
	void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

}

According to the source code, we know that there is only one method postprocessbeandefinitionregistry (BeanDefinitionRegistry). This method is obviously born for the registration of beans. Bean definitionregistry is the register of BeanDefinition, and the process of registering beans is to resolve classes that meet the conditions of beans into BeanDefinition objects and then register them in the BeanDefinition register.

Summary

BeanFactoryPostProcessor and BeanDefinitionRegistryPostProcessor are both extended Bean loading methods. When we need to customize our own Bean loading methods, we can implement the BeanDefinitionRegistryPostProcessor interface@ The implementation of the Configuration annotation is based on the BeanDefinitionRegistryPostProcessor interface.

Beanfactoryprocessor principle

Readers who have read the spring source code are well aware that refresh() in the AbstractApplicationContext class is the core method for spring to load beans. Most of the processing logic is completed in this method. The code is as follows:

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

			// Prepare this context for refreshing.
			/**
			 * Prepare context refresh work, such as setting initial values
			 */
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			/**
			 * Tell the subclass to refresh the internal beanFactory and return to the Bean factory
			 */
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			/**
			 * Prepare beanFactory for use in context
			 */
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				/**
				 * Allows post-processing of bean factories in context subclasses.
				 */
				postProcessBeanFactory(beanFactory);

				/**
				 * Turn on the PostProcessors step processor
				 */
				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
				// Invoke factory processors registered as beans in the context.
				/**
				 * Calling the post processor of BeanFactory
				 */
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				/**
				 *
				 * Register the bean processor created by the intercepting bean
				 */
				registerBeanPostProcessors(beanFactory);
				/**
				 * Processing PostProcessors steps
				 */
				beanPostProcess.end();

				// Initialize message source for this context.
				/**
				 * Initialize MessageSource
				 */
				initMessageSource();

				// Initialize event multicaster for this context.
				/**
				 * Initialize the management Bean of the Application listener (applicationeventmulticast)
				 */
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				/**
				 * Template mode, the operation of refreshing beans, and the specific logic is implemented by subclasses
				 */
				onRefresh();

				// Check for listener beans and register them.
				/**
				 * Check and register listeners
				 */
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				/**
				 * Instantiate all (non lazy initialization) singletons
				 */
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				/**
				 * Publish corresponding events
				 */
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
				contextRefresh.end();
			}
		}
	}

According to the source code, it is found that spring implements the specific logic of beanfactoryprocessors in the invokebeanfactoryprocessors (beanfactory) method. The processing logic is analyzed according to this method.

invokeBeanFactoryPostProcessors

	protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
		/**
		 * Executing beanfactoryprocessor is the processing core of this method
		 */
		PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

		// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
		// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
		/**
		 * Check and assign initial values
		 */
		if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}
	}

The core of logical processing is postprocessor registrationdelegate The invokebeanfactoryprocessors (beanfactory, getbeanfactoryprocessors()) method is analyzed as follows:

public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
		Set<String> processedBeans = new HashSet<>();

		/**
		 * First call BeanDefinitionRegistryPostProcessors (if any).
		 */
		if (beanFactory instanceof BeanDefinitionRegistry) {
			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
			/**
			 * The object used to hold the beanfactoryprocessor
			 */
			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
			/**
			 * The user stores the BeanDefinitionRegistryPostProcessor object
			 */
			List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();


			/********************************* The following processes the BeanDefinitionRegistryPostProcessor logic*************************************/


			/**
			 * Traverse the original beanfactory postprocessor list to find BeanDefinitionRegistryPostProcessor and beanfactory postprocessor
			 * BeanDefinitionRegistryPostProcessor Is a sub interface of beanfactoryprocessor
			 */
			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
					BeanDefinitionRegistryPostProcessor registryProcessor =
							(BeanDefinitionRegistryPostProcessor) postProcessor;
					/**
					 * Execute the postProcessBeanDefinitionRegistry of BeanDefinitionRegistryPostProcessor
					 */
					registryProcessor.postProcessBeanDefinitionRegistry(registry);
					registryProcessors.add(registryProcessor);
				}
				else {
					regularPostProcessors.add(postProcessor);
				}
			}

			/**
			 * Defines the currently found BeanDefinitionRegistryPostProcessor temporary store
			 */
			List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

			// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
			// First, call the BeanDefinitionRegistryPostProcessor that implements PriorityOrdered.
			String[] postProcessorNames =
					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
			currentRegistryProcessors.clear();

			// Next, call the BeanDefinitionRegistryPostProcessor that implements Ordered.
			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
			currentRegistryProcessors.clear();

			// Finally, call all other BeanDefinitionRegistryPostProcessor until there is no other BeanDefinitionRegistryPostProcessor.
			boolean reiterate = true;
			while (reiterate) {
				reiterate = false;
				postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
				for (String ppName : postProcessorNames) {
					if (!processedBeans.contains(ppName)) {
						currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
						processedBeans.add(ppName);
						reiterate = true;
					}
				}
				sortPostProcessors(currentRegistryProcessors, beanFactory);
				registryProcessors.addAll(currentRegistryProcessors);
				invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
				currentRegistryProcessors.clear();
			}

			/**
			 * Batch execution of postProcessBeanDefinitionRegistry of BeanDefinitionRegistryPostProcessor
			 */
			invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
			/**
			 * Batch execution of beanfactoryprocessor (the first beanfactoryprocessor)
			 */
			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
		}

		else {
			// Invoke factory processors registered with the context instance.
			invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
		}

		/********************************* Next, process the beanfactory postprocessor logic (the above steps may be performed to generate a new beanfactory postprocessor), and the execution logic is consistent with the BeanDefinitionRegistryPostProcessor*************************************/

		// Do not initialize FactoryBeans here: We need to leave all regular beans
		// uninitialized to let the bean factory post-processors apply to them!
		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);
		invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

		// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
		List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
		for (String postProcessorName : orderedPostProcessorNames) {
			orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		sortPostProcessors(orderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

		// Finally, invoke all other BeanFactoryPostProcessors.
		List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
		for (String postProcessorName : nonOrderedPostProcessorNames) {
			nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

		// Clear cached merged bean definitions since the post-processors might have
		// modified the original metadata, e.g. replacing placeholders in values...
		beanFactory.clearMetadataCache();
	}


	/**
	 * Sort beanfactoryprocessor
	 * @param postProcessors
	 * @param beanFactory
	 */
	private static void sortPostProcessors(List<?> postProcessors, ConfigurableListableBeanFactory beanFactory) {
		// Nothing to sort?
		if (postProcessors.size() <= 1) {
			return;
		}
		Comparator<Object> comparatorToUse = null;
		if (beanFactory instanceof DefaultListableBeanFactory) {
			comparatorToUse = ((DefaultListableBeanFactory) beanFactory).getDependencyComparator();
		}
		if (comparatorToUse == null) {
			comparatorToUse = OrderComparator.INSTANCE;
		}
		postProcessors.sort(comparatorToUse);
	}


	/**
	 * Execute BeanDefinitionRegistryPostProcessor
	 * @param postProcessors
	 * @param registry
	 * @param applicationStartup
	 */
	private static void invokeBeanDefinitionRegistryPostProcessors(
			Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry, ApplicationStartup applicationStartup) {

		for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
			StartupStep postProcessBeanDefRegistry = applicationStartup.start("spring.context.beandef-registry.post-process")
					.tag("postProcessor", postProcessor::toString);
			postProcessor.postProcessBeanDefinitionRegistry(registry);
			postProcessBeanDefRegistry.end();
		}
	}


	/**
	 * Execute invokebeanfactoryprocessors
	 * @param postProcessors
	 * @param beanFactory
	 */
	private static void invokeBeanFactoryPostProcessors(
			Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {

		for (BeanFactoryPostProcessor postProcessor : postProcessors) {
			StartupStep postProcessBeanFactory = beanFactory.getApplicationStartup().start("spring.context.bean-factory.post-process")
					.tag("postProcessor", postProcessor::toString);
			postProcessor.postProcessBeanFactory(beanFactory);
			postProcessBeanFactory.end();
		}
	}

	

The above is the specific logic for spring to execute beanfactoryprocessor. The execution process is very clear. The execution steps are as follows:

  • Step 1: traverse the original beanfactoryprocessor, find BeanDefinitionRegistryPostProcessor and beanfactoryprocessor, and execute the postProcessBeanDefinitionRegistry(registry) method of BeanDefinitionRegistryPostProcessor to load the Bean.

  • Step 2: find the PriorityOrdered type Bean of BeanDefinitionRegistryPostProcessor from BeanFactory. After sorting, execute the postProcessBeanDefinitionRegistry(registry) method to load the Bean.

  • Step 3: find the Ordered type beans of BeanDefinitionRegistryPostProcessor that are not loaded from BeanFactory. After sorting, execute the postProcessBeanDefinitionRegistry(registry) method to load the beans.

  • Step 4: find the unloaded BeanDefinitionRegistryPostProcessor type Bean from BeanFactory, and then execute the postProcessBeanDefinitionRegistry(registry) method to load the Bean. The purpose of this step is to process the Bean that loads the new BeanDefinitionRegistryPostProcessor.

  • Step 5: find the PriorityOrdered (highest priority sorting) type Bean of BeanFactory postprocessor from BeanFactory. After sorting, execute the postProcessBeanFactory(beanFactory) method to load the Bean.

  • Step 6: find the Ordered type Bean whose BeanFactory postprocessor is not loaded from BeanFactory. After sorting, execute the postProcessBeanFactory(beanFactory) method to load the Bean.

  • Step 7: find out the unordered BeanFactory postprocessor type Bean from BeanFactory, and then execute the postProcessBeanFactory(beanFactory) method to load the Bean.

summary

Bean factorypostprocessor is the earliest post processor. Understanding its principle is very helpful for us to develop spring plug-ins. In particular, the BeanDefinitionRegistryPostProcessor interface extends the diversity of spring loaded beans. I hope to help readers know what it is and why it is from the perspective of source code.

Topics: Java Spring