Spring source code analysis - beanfactoryprocessor

Posted by Braimaster on Sun, 31 Oct 2021 04:42:02 +0100

Spring source code analysis - beanfactoryprocessor

The blogger's technology is limited, so this article will inevitably make mistakes. If you find it, please comment and point it out in a private letter. Thank you

The beanfactoryprocessor interface is an extension point for beans provided by Spring. Its sub interface is BeanDefinitionRegistryPostProcessor

@FunctionalInterface
public interface BeanFactoryPostProcessor {
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}


public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
	void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}

Beanfactoryprocessor is easy to use

The execution time of beanfactoryprocessor is after the Spring scan is completed and before the Bean initialization. When we implement the beanfactoryprocessor interface, we can modify the properties of the Bean before the initialization of the Bean

@Component
public class A {
}

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		BeanDefinition beanDefinition = beanFactory.getBeanDefinition("a");
		beanDefinition.setScope("prototype");
	}
}

@Configuration
@ComponentScan("com.jame")
public class Myconfig {
}

public class MyTest {
	public static void main(String[] args)  {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Myconfig.class);
		A a = context.getBean(A.class);
		A a1 = context.getBean(A.class);
		System.out.println(a==a1);
    }
}

The output result is: false

In the above example, we set the scope of a's beanDefinition as the prototype. When the scope is not set by default, the scope of the bean is a single instance, that is, we successfully modified the beanDefinition of object A. There are more than one attributes that can be modified, as well as lazy loading, initialization method name, setting attributes, etc

Its subclass BeanDefinitionRegistryPostProcessor can operate on the BeanDefinition in the spring container

If you don't know about BeanDefinition, you can simply understand it as a class that wraps Java classes. For example, whether we set a singleton for the class and whether it is lazy to load these information needs to be stored. spring creates a BeanDefinition to store other information except Java classes

BeanDefinitionRegistryPostProcessor is easy to use

@Component
public class A {
}

public class B  {
}

@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

	@Override
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
		RootBeanDefinition beanDefinition = new RootBeanDefinition(B.class);
		registry.registerBeanDefinition("b",beanDefinition);
		registry.removeBeanDefinition("a");
	}

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
	}
}

@Configuration
@ComponentScan("com.jame")
public class Myconfig {
}

public class MyTest {
	public static void main(String[] args)  {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Myconfig.class);
		B b = context.getBean(B.class);
		System.out.println(b);
		A a = context.getBean(A.class);
    }
}

Output results:

com.jame.pojo.B@2ac1fdc4
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.jame.pojo.A' available......

In the above code, we added @ component to class A and nothing to class B. the result should be that a obtains normal output, and then obtains B, but the error cannot be found. However, the result is just the opposite, because we modified the Bean managed by Spring in the MyBeanDefinitionRegistryPostProcessor class, added a BeanDefinition of B and deleted the BeanDefinition of A, So the result is as shown above

After completing the above simple use case, let's start to see what the implementation principle of Spring is

Source code analysis

First, the first step is to know when to execute the above code. For convenience, you don't need to paste the search process. You can output sentences in the implementation class and Debug to see which method is output

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
   this();
   register(componentClasses);
   refresh();
}

Enter the refresh method

@Override
public void refresh() throws BeansException, IllegalStateException {
......
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);

// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
........
}
}

Enter the invokebeanfactoryprocessors method

public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

		Set<String> processedBeans = new HashSet<>();

		if (beanFactory instanceof BeanDefinitionRegistry) {
			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
            
			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
			List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
					BeanDefinitionRegistryPostProcessor registryProcessor =
							(BeanDefinitionRegistryPostProcessor) postProcessor;
					registryProcessor.postProcessBeanDefinitionRegistry(registry);
					registryProcessors.add(registryProcessor);
				} else {
					regularPostProcessors.add(postProcessor);
				}
			}
            
			List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

			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);
			currentRegistryProcessors.clear();

			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);
			currentRegistryProcessors.clear();
            
			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);
				currentRegistryProcessors.clear();
			}

			invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
		} else {
			invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
		}

		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

		List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
		List<String> orderedPostProcessorNames = new ArrayList<>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
		for (String ppName : postProcessorNames) {
			if (processedBeans.contains(ppName)) {
                
			} 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);
			}
		}

		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

		List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
		for (String postProcessorName : orderedPostProcessorNames) {
			orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		sortPostProcessors(orderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

		List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
		for (String postProcessorName : nonOrderedPostProcessorNames) {
			nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
		beanFactory.clearMetadataCache();
	}

Look at the top definition

Set<String> processedBeans = new HashSet<>();

This is also easy to understand. It stores the name of the executed beanfactoryprocessor to prevent repeated execution

if (beanFactory instanceof BeanDefinitionRegistry) {
			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;

			//Store the implementation classes that directly implement beanfactoryprocessor and have been processed / found
			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();

			//Store directly implemented BeanDefinitionRegistryPostProcessor, processed / found implementation classes
			List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
					BeanDefinitionRegistryPostProcessor registryProcessor =
							(BeanDefinitionRegistryPostProcessor) postProcessor;
					registryProcessor.postProcessBeanDefinitionRegistry(registry);
					registryProcessors.add(registryProcessor);
				} else {
					regularPostProcessors.add(postProcessor);
				}
			}

Let's look at the first if judgment to judge whether the incoming BeanFactory is of BeanDefinitionRegistry type. In most cases, it is always true by default

Then, two sets are defined above to store the processed implementation classes. (there is already a set storage name on it. Why do we need to build two sets to store

The following for loop only has a value for the beanfactoryprocessor set through the api. What does it mean? Look down

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Myconfig.class);context.addBeanFactoryPostProcessor(new MyBeanFactoryPostProcessor());

Why not? Because of the problem of the running sequence of our code, let's look at the use code above. First, we need to create a new AnnotationConfigApplicationContext(MyConfig.class)

The refresh - > invokebeanfactorypostprocessors - > invokebeanfactorypostprocessors method has been called in its construction

When we debug, we haven't reached context. Addbeanfactoryprocessor (New mybeanfactoryprocessor()); Method, so it is empty

How do you use it? Let's take a closer look at the construction of AnnotationConfigApplicationContext

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {    this();    register(componentClasses);    refresh();}

There are only three methods. You can call yourself no parameter, register and refresh, and execute invokebeanfactoryprocessors in the refresh method, that is, we can register before the refresh method

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();context.register(Myconfig.class);context.addBeanFactoryPostProcessor(new MyBeanFactoryPostProcessor());context.refresh();

In this way, we can manually call the api before the refresh method

Keep going

if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {    BeanDefinitionRegistryPostProcessor registryProcessor =        (BeanDefinitionRegistryPostProcessor) postProcessor;    registryProcessor.postProcessBeanDefinitionRegistry(registry);    registryProcessors.add(registryProcessor);} else {    regularPostProcessors.add(postProcessor);}

It is judged that it is the BeanDefinitionRegistryPostProcessor type. If so, it will be executed directly. Otherwise, it will be added to the collection. Remember this collection? It is in the outermost if

if (beanFactory instanceof BeanDefinitionRegistry) {    BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;    //Store directly implemented beanfactoryprocessor, processed / found implementation class list < beanfactoryprocessor > regularpostprocessors = new ArrayList < > ()// Store directly implemented BeanDefinitionRegistryPostProcessor, processed / found implementation class list < BeanDefinitionRegistryPostProcessor > registryprocessors = new ArrayList < > ();...}

If not, it will be added to the regularPostProcessors collection. Why does this type not execute? It is related to the execution order of Spring. Wait until the end

From list currentregistryprocessors = new ArrayList < > (); Create this collection and start looking down

List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();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);currentRegistryProcessors.clear();

First, what does this collection do: it is used to store the BeanDefinitionRegistryPostProcessor that needs to be executed at present

A good understanding of the BeanDefinitionRegistryPostProcessor to be executed. What is the current?? In advance, this collection is reused below. The current is the currently executing BeanDefinitionRegistryPostProcessor. The type is a class. Look down first and explain later

First, it creates a string array to receive the return parameters of beanFactory.getBeanNamesForType. Briefly, the function of this method

Find the name of the BeanDefinition whose type is the incoming type from BeanDefinitionNames

The call chain is defaultlistablebeanfactory.getbeannamesfortype - > defaultlistablebeanfactory.dogetbeannamesfortype. If you are interested, you can go and have a look

Let's debug to see who gets the beanName of type BeanDefinitionRegistryPostProcessor

So keep going down

if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)), check whether the BenaDefinition of the passed PostProcessorName conforms to PriorityOrdered.class. Of course, this method is more than that. We will only analyze the relevant

PriorityOrdered is a sorting interface. Its parent class is Ordered. The smaller the value, the first to call it. You can simply understand it first, which is not the focus of this chapter

public interface PriorityOrdered extends Ordered {}public interface Ordered {	int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;	int LOWEST_PRECEDENCE = Integer.MAX_VALUE;	int getOrder();}

Leave a question. When did this BeanDefinition come in? First, continue to look at the code as a whole and return true to enter the judgment

currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));

The main focus is on the getBean method. In the future, I will have the opportunity to write a separate article on getBean, which is simply understood as obtaining the class from the Spring container. If it does not exist, find the corresponding BeanDefinition from the BeanDefinitionMap, and then instantiate it back

So suppose we have obtained the instantiated java object, who is it? debug

Remember this class ConfigurationClassPostProcessor

Then, the name of the current class is stored in the processed set at the top of the method

//Stores the name of the beanfactoryprocessor that has completed processing
Set<String> processedBeans = new HashSet<>();

After that, the sorting method is called, then the BeanFactoryPostProcessor that has been processed is stored in List.

//Store the processed implementation classes that directly implement BeanDefinitionRegistryPostProcessor
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

Let's focus on invokebean definition registry postprocessors (current registry processors, registry); method

private static void invokeBeanDefinitionRegistryPostProcessors(    Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {    for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {        postProcessor.postProcessBeanDefinitionRegistry(registry);    }}

The ConfigurationClassPostProcessor found above is the top priority. Spring scanning is completed in this class. How to prove it? Debug

Let's look at the number of beandefinitionmaps in beanFactory

I have a chance to write an article about Spring after scanning

Then, clear the List collection currently being executed and continue down

postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {    //It is judged here that if the current BeanDefinitionRegistryPostProcessor is not found in the stored collection / / that is to say, it has not been executed yet, put it into the currently executed collection for the next operation 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); / / execute the same code as the postProcessBeanFactory method invokebeanefinitionregistrypostprocessors (currentRegistryProcessors, registry);currentRegistryProcessors.clear();

What is found? The code is very similar to the above, so we won't repeat it, but simply talk about the key points

if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) 

In addition to the processed ones, the judgment prevents repeated execution, and then the judgment type. The above type is PriorityOrdered, and now it is Ordered

So let's see

 currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));

This set is the set just defined to store "current processing"

List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

What is current processing? At the beginning of execution, this collection stores classes that implement the PriorityOrdered interface. For the above, the "current processing" is to implement the priortyordered class, and then the code is executed to currentRegistryProcessors.clear(); for the classes that implement the PriorityOrdered interface, the "current processing" The collection of is no longer the implementation class that stores the PriorityOrdered interface

Here, only the Ordered type is stored in the list, so "currently processed" refers to the class implementing the Ordered interface. Because its collection is reused in many places, it is called "currently processed" collection

The following code should be able to understand. The BeanDefinitionRegistryPostProcessor that implements priorityordered and ordered has been executed. Finally, the BeanDefinitionRegistryPostProcessor that does not implement both has been executed

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);    currentRegistryProcessors.clear();}

Then there may be a question

registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);

This has been implemented. Why do you want to put the collection? Please note that the interface you are looking for is the implementation class of BeanDefinitionRegistryPostProcessor, not beanfactoryprocessor. So, A simple basic java question, A class implements interface A, and interface A inherits interface B. do you need to implement the methods defined by interface B? The answer is yes, so the above is only implementation Line is the method defined in the BeanDefinitionRegistryPostProcessor interface, so you can see it at A glance from the last two lines

//Why pass in a collection of beandefinitionregisterpost processes that have already been executed?
//Because our custom class implements the beandefinitionregisterpost process interface
//This interface inherits beanfactorypost process, so we need to implement not only the methods of the child class, but also the methods of the parent class
//In the above processing, only the methods of the child class are called, so the methods of the parent class are called again here
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);

OK, so far, use the post processor added by Api to complete, but have you found a small problem? Every time, the post processor names are obtained again. Why not obtain them once and use them all the time?

Let's look back at the simple use case of starting to use BeanDefinitionRegistryPostProcessor. Assuming that the class implementing the PriorityOrdered interface modifies the number of beans after calling the postProcessBeanDefinitionRegistry method, the data obtained in the following operations are not up-to-date. In order to solve this problem, we need to obtain it again every time

Continue down. The following code is the beanfactoryprocessor implementation class we found by scanning or xml

String[] postProcessorNames =    beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);// Separate between beanfactoryprocessors that implement priorityOrdered, / / ordered, and the rest. / / respectively store the name sets that implement the priorityOrdered interface, the ordered interface, and the ordered interface. List < beanfactoryprocessor > priorityordedpostprocessors = new ArrayList < > (); list < string > orderdprocessornames = 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<>();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<>();for (String postProcessorName : nonOrderedPostProcessorNames) {    nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}invokeBeanFactoryPostProcessors (nonOrderedPostProcessors, beanFactory);

The following code is relatively simple. Just write it down

First, use beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false); get the name of the implementation class whose type is BeanFactoryPostProcessor, and then judge whether the PriorityOrdered interface is implemented, whether the Ordered interface is implemented, or whether neither is implemented

Put them into the corresponding set respectively, and then execute them in sequence

Let's sort out the order of execution

  1. Add a class that implements BeanDefinitionRegistryPostProcessor through Api
  2. Spring built in
    1. Implement the PriorityOrdered interface
    2. Implement the Ordered interface
    3. Neither has been achieved
  3. Add classes that implement beanfactoryprocessor through Api
  4. Execute classes that implement BeanFactoryPostProcessor and PriorityOrdered by scanning / xml configuration
  5. Execute the classes that implement BeanFactoryPostProcessor and Ordered by scanning / xml configuration
  6. Execute the class that implements beanfactoryprocessor by scanning / xml configuration

Let's write code and demonstrate it

The overall structure is as follows

@Component
public class BDPP implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("I didn't implement any sort interface");
    }
}


@Component
public class BDPPOrdered0 implements Ordered, BeanFactoryPostProcessor {
    @Override
    public int getOrder() {return 0;}
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("realization Ordered of BDPP,Sort 0");
    }
}

@Component
public class BDPPOrdered1 implements Ordered, BeanFactoryPostProcessor {
    @Override
    public int getOrder() {return 1;}
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("realization Ordered of BDPP,Sort 1");
    }
}


@Component
public class BDPPPriorityOrdered0 implements PriorityOrdered, BeanFactoryPostProcessor {
    @Override
    public int getOrder() {return 0;}
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("realization PriorityOrdered of BDPP,Sort 0");
    }
}

@Component
public class BDPPPriorityOrdered1 implements PriorityOrdered, BeanFactoryPostProcessor {
    @Override
    public int getOrder() {return 1;}

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("realization PriorityOrdered of BDPP,Sort 1");
    }
}


public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        System.out.println("Api Added BeanDefinitionRegistryPostProcessor,I am the method of the interface");
    }
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("Api Added BeanDefinitionRegistryPostProcessor,I am the parent interface method");
    }
}


public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("Api Added BeanFactoryPostProcessor");
    }
}


public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(Myconfig.class);
    context.addBeanFactoryPostProcessor(new MyBeanFactoryPostProcessor());
    context.addBeanFactoryPostProcessor(new MyBeanDefinitionRegistryPostProcessor());
    context.refresh();
}

Add a sentence to the Spring scan method for output

Other Spring built-in will not be added. Let's see the results

That is, if you want to perform some operations on the Bean before Spring finishes scanning, you can implement the BeanDefinitionRegistryPostProcessor interface and add it manually. The above output also shows that when inheriting PriorityOrdered or Ordered, those with small values should be executed first

Another problem is that when we obtain the beanfactory postprocessor, we obtain the name again every time before using it, but only once when we obtain the beanfactory postprocessor configured by scanning or Xml below

String[] postProcessorNames =    beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

Because the beanfactoryprocessor interface only enhances beans and does not delete new ones

Answer the above question: when did the BeanDefinition of this ConfigurationClassPostProcessor come in

Let's look at the parameterless construction of new AnnotationConfigApplicationContext()

public AnnotationConfigApplicationContext() {
    //The bd built into spring will be registered here
    this.reader = new AnnotatedBeanDefinitionReader(this);
    this.scanner = new ClassPathBeanDefinitionScanner(this);
}
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    Assert.notNull(environment, "Environment must not be null");
    this.registry = registry;
    this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
    //here
    AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
    BeanDefinitionRegistry registry, @Nullable Object source) {
    .....
        if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
        }
    .......
}

Remember the first time you passed String[] postProcessorNames above=
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);

Look at configuration_ ANNOTATION_ PROCESSOR_ BEAN_ What is the value of the constant name

public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME =
    "org.springframework.context.annotation.internalConfigurationAnnotationProcessor";

And its if judgment is

@Override
public boolean containsBeanDefinition(String beanName) {
    Assert.notNull(beanName, "Bean name must not be null");
    return this.beanDefinitionMap.containsKey(beanName);
}

That is, during initialization, if it does not exist, register beanDefinition. The specific registration method is from

beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));

registry.registerBeanDefinition(beanName, definition);

DefaultListableBeanFactory.registerBeanDefinition is the method of registering beanDefinition. If you are interested, you can click to have a look

Topics: Spring