Ps: Bean initialization is so much covered that I have to split it into two parts

  • Part 1: Mainly explains the related content of BeanFactory, including the related content of the post-processor
  • The next chapter focuses on Bean instantiation

What is Bean??

What is bean? Springbeans are a simple shorthand: classes that are initialized, assembled, and managed by the Spring container, and whose life cycle is governed by Spring.

1, bean configuration mode (familiar friends can skip directly)

(1) XML configuration

XML configuration is an early configuration way, after the emergence of SpringBoot gradually eliminated, configuration items are complex, look chaotic, some partners into the pit for a short time, or even do not have access to XML configuration, a simple demonstration, we see a lively. Create a bean before the first to have a class, SpringBoot can not be created out of thin air, I do not know if you have female tickets, not small friends today lucky, today one person hair a!! Ohhhhhhhhhhhh!!!!!! Open up a GirlFriend using SpringBoot New to stimulate a custom GirlFriend thief.

public class GirlFriend{
    private String name;
    private Integer age;
    private Integer height;
    private Integer weight;
    private List<String> hobby;
    
    public GirlFriend(a){}
    
    public GirlFriend(String name,Integer age){
        this.name = name;
        this.age = age; }... GetSet to omit... }Copy the code

Have a girlfriend also need to take Home, and define a Home

public class Home{
    privateGirlFriend girlFriend; . GetSet to omit... }Copy the code
1) No-parameter construction

Create an XML file in Resources and call it whatever you want, first-love-girl.xml

<?xml version="1.0" encoding="UTF-8">
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <! -- Took notes!! XMLNS: a file address for initializing beans XMLNS :xsi: a file address for initializing beans Auxiliary initialization bean xsi:schemaLocation: used for schema documents that declare the target namespace --> <! Create a bean with id: unique representation,class: full path name --> <bean id="girlFriend" class="com.gyx.test.GirlFriend"> <! Assign a value to a propertynameAttribute name:value: injected value --> <property name="name" value="cuiHua"/ > <! -- Boys like girls of eighteen.property name="age" value18 = "" / > <property name="hobby">
            <list>
                <value< / > reading a bookvalue>
                <value> Eat snacks </value>
            </list>
        </property>
    </bean>
    
    <bean id="home" class="com.gyx.test.Home"> <! - the use ofrefTo reference the one already definedbeanObject - > <property name="girlFriend" ref="girlFriend"/ > < /bean>
</beans>
Copy the code
2) Parametric construction
. The repetition above skipped....<! Create a bean with id: unique representation, class: full path name -->
    <bean id="girlFriend" class="com.gyx.test.GirlFriend">
        <! Index: the position of the argument starts at 0, value: the value of the argument -->
        <construcort-arg index="0" value="cuiHua">
        <construcort-arg index="1" value="18">
        <property name="hobby">
            <list>
                <value>Reading a book</value>
                <value>Eating snacks</value>
            </list>
        </property>
    </bean>. .... is also repeated belowCopy the code
3) Static factory method

With the growth of business, in order to solve the single problem of the majority of male compatriots, manual creation has been unable to meet the demand, set up factories for mass production

I. Define abstract classes
public abstract class GirlFriend{
    abstract String getName(a);
}
Copy the code
Ii. Implement abstract classes

The girl

public class Loli extends GirlFriend {
    @Override
    String  getName(a){
        returnname; }}Copy the code

The queen

public class Queen extends GirlFriend {
    @Override
    String  getName(a){
        returnname; }}Copy the code
Iii. Implement static factories
public class GirlFriendFactory {
    @Override
    public static GirlFriend  getGirlFriend(String type){
        if("queen".equals(type)){
            return new Queen();
        } else if("loli".equals(type)) {
            return new Loli();
        }else {
            return null; }}}Copy the code
Iv. The XML configuration
. The repetition above skipped....<! Create a bean with id: unique representation, class: full pathname, factory-method: factory method -->
    <bean id="loli" class="com.gyx.test.GirlFriendFactory" factory-method="getGirlFriend">
        <! Pass in parameters -->
        <construcort-arg  value="queen">
    </bean>. .... is also repeated belowCopy the code
4) Example factory method
I. Create an instance factory
public class GirlFriendFactory {
    @Override
    public GirlFriend  getGirlFriend(String type){
        if("queen".equals(type)){
            return new Queen();
        } else if("loli".equals(type)) {
            return new Loli();
        }else {
            return null; }}}Copy the code
Ii. The XML configuration
. The repetition above skipped....<bean name="girlFriendFactory" class="com.gyx.test.GirlFriendFactory">
<! Create a bean with id: unique representation, factory-bean: factory-method: factory-method -->
<bean id="loli" factory-bean="girlFriendFactory" factory-method="getGirlFriend">
        <! Pass in parameters -->
        <construcort-arg  value="loli">
</bean>. .... is also repeated belowCopy the code

(2) Java code configuration of beans

1) @Component annotation configuration Bean (@service, @Controller are the same)
@Component
public class GirlFriend{
    private String name;
    private Integer age;
    private Integer height;
    private Integer weight;
    private List<String> hobby;
    
    public GirlFriend(a){}
    
    public GirlFriend(String name,Integer age){
        this.name = name;
        this.age = age; }... GetSet to omit... }Copy the code
2) @bean annotations configure beans
@Configuration
public class BeanConfiguration{
    @Bean
    public GirlFriend getGirlFriend(a){
        return new GirlFriend("cuihua".18); }}Copy the code
3) Configure beans using the FactoryBean interface
@Component
public class MyGirlFriend implements FactoryBean<GirlFriend>{
    @Override
    public GirlFriend getObject(a) throws Exception{
        return newLoli(); }}Copy the code
4) use BeanDefinitionRegistryPostProcessor interface configuration Bean
@Component
public class MyGirlFriend implements BeanDefinitionRegistryPostProcessor{
    // Register a bean object
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException{
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
        rootBeanDefinition.setBeanClass(Queen.class);
        registry.registerBeanDefinition("queen",rootBeanDefinition);
    }
    
    // This method injects values into bean objects
    @Override
    public void postProcessBeanFactory(ConfiguraleListableBeanFactory beanFactory) throws BeansException{
        // Get the definition of the bean object you just defined
        BeanDefinition queen = beanFactory.getBeanDefinition("queen");
        // Add attribute values to the object
        MutablePropertyValues propertyValues = queen.getPropertyValues();
        propertyValues.addPropertyValue("name".Red Wolf); }}Copy the code
5) use ImportBeanDefinitionRegistrar interface configuration Bean
public  class MyGirlFriend implements ImportBeanDefinitionRegistrar{
     @Override
     public void registerBeanDefinition(AnnotationMetadata importingClassMetadata,BeanDefinitionRegistry registry){
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
        rootBeanDefinition.setBeanClass(Queen.class);
        registry.registerBeanDefinition("queen",rootBeanDefinition); }}Copy the code

The bean creation process

In the previous chapter, we learned how to create beans in chapter 9, so how does SpringBoot create girlfriends? No, no, no, no, no. The process of creating and loading beans is encapsulated in the refresh method. This method is commonly referred to as “bean life point · Spring startup key · interview question ·refresh”. I don’t know if you fully understood this before, but it doesn’t matter! Not 998 today, not 99.8! A single article takes you straight to the point where you can fully understand the refresh method without saying much! SpringBoot together in the heart of it!!

Find the location of the refresh method

Step 1: To take care of new friends, we’ll start with the Boot class of SpringBoot and work our way through

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        // Enter the run methodSpringApplication.run(Application.class, args); }}Copy the code

Step 2: ConfigurableApplicationContext class

public static ConfigurableApplicationContext run(Class
        primarySource, String... args) {
       // enter the run method again
		return run(newClass<? >[] { primarySource }, args); }Copy the code

Step 3: Enter the run method again

public static ConfigurableApplicationContext run(Class
       [] primarySources, String[] args) {
       // Continue clicking on the run method
       // What is the run constructor doing
       // Go ahead and catch up on the first article in this series, the answer is in there
		return new SpringApplication(primarySources).run(args);
}
Copy the code

Step 4: Ok! We again SpringBoot heart method, specific comments here at https://blog.csdn.net/qq_34886352/article/details/104949485

	public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            // This name looks similar to the target method
            // Context is the context of the application, where many of the configured properties are stored
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
			}
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}

		try {
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}
Copy the code

Step 5: The Refresh method is here

private void refreshContext(ConfigurableApplicationContext context) {
    // I found it! Dangdang when! The refresh method sits quietly here, unremarkable and in fact deadly
    refresh(context);
    if (this.registerShutdownHook) {
        try {
            // This method registers a hook on the JVM to ensure that the container is closed properly when the program is closed
            context.registerShutdownHook();
        }
        catch (AccessControlException ex) {
            // Not allowed in some environments.}}}Copy the code

Refresh in the refresh method

Step 6: The first layer of the refresh method

protected void refresh(ApplicationContext applicationContext) {
    // Refresh method is not lost for military purposes! Just as he entered, he was confronted by a guard
    / / whether the incoming parameters for AbstractApplicationContext subclasses, if not directly
    Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
    // To perform type force, continue to click refresh method
    / / here will find that there are three implementations, some AbstractApplicationContext class
    ((AbstractApplicationContext) applicationContext).refresh();
}
Copy the code

Step 7: You can see that Refresh is a boss-level approach! But don’t panic. There are many ways we can take them one by one

@Override
	public void refresh(a) throws BeansException, IllegalStateException {
        // This method is locked, and only one thread needs to execute the current method at a time
		synchronized (this.startupShutdownMonitor) {
			// Ready to refresh! Some preparation before the actual construction
          / / step 8
			prepareRefresh();

			// Get the bean factory
          / / step 9
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Do some configuration for the beanFactory
          // Add dependencies to be ignored, classloaders, post-handlers, parsers, etc., and aOP-related post-handlers are also configured here
          / / step 12
			prepareBeanFactory(beanFactory);

			try {
				// Do some post-processing on the BeanFactory in context
                / / by default is an empty implementation, but we will mainly as a web service operation, will go to AnnotationConfigServletWebServerApplicationContext class, don't go the wrong way
                // Registers handlers, beans, and configurations related to web requests
                / / step 13
				postProcessBeanFactory(beanFactory);

                Instantiate and invoke the bean factory-registered post-processor, which must be performed before the singleton bean is created
                / / step 15
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register the backend handler used for bean creation
              / / step 17
				registerBeanPostProcessors(beanFactory);

				// Initializes the message source for this context, internationalizing the process
                //messageSource is used for internationalization
                    // Determine if the BeanFactory contains a messageSource, if not, create one
                    / / step 19
				initMessageSource();

				// Initializes the event broadcaster, part of the Spring listener
                / / step 20
				initApplicationEventMulticaster();

				// Initialize specific beans based on context
                / / if it is a web environment, will enter the ServletWebServerApplicationContext implementation
                // This method mainly creates a Web container, such as the Tomcat container embedded in SpringBoot
                // We'll skip this for now and parse it in more detail in future updates
				onRefresh();

				// Register the listener
                // Add the listener implementation to the broadcaster
                / / step 21
				registerListeners();

				// Initialize the singleton bean
               // This will be explained in the next article
               // This is a very important question
				finishBeanFactoryInitialization(beanFactory);

				// Clear the cache and send the ContextRefreshedEvent event
                / / step 22
				finishRefresh();
			}

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

				// Destroy the singleton bean that has been created
				destroyBeans();

				// Change the state of the 'active' property
				cancelRefresh(ex);

				// Throw an exception
				throw ex;
			}

			finally {
				// Delete all caches to prevent too much memory usage, after all, the execution failed, the data is uselessresetCommonCaches(); }}}Copy the code

(1) Preliminary preparation

Step 8: Get ready to refresh! Some preparation before the actual construction

// Some friends version may not be the same as mine, but when you enter it, you find that it is not the same content, do not need to click the same method on the line
protected void prepareRefresh(a) {
        // Record the startup time
		this.startupDate = System.currentTimeMillis();
        // Change the state of the context to active, indicating that the context is about to start busy, do not disturb it
		this.closed.set(false);
		this.active.set(true);
        // In debug mode, some logs will be printed, which will not be read anyway
		if (logger.isDebugEnabled()) {
			if (logger.isTraceEnabled()) {
				logger.trace("Refreshing " + this);
			}
			else {
				logger.debug("Refreshing "+ getDisplayName()); }}// Initialize any placeholder property sources in the context environment
        // Initialize the property
        // This is version 2.1.0 and this method is empty
		initPropertySources();

		// Check key attributes. If the required attributes are empty, an exception will be thrown
		/ / details view: ConfigurablePropertyResolver# setRequiredProperties
		getEnvironment().validateRequiredProperties();

		// Initialize earlyApplicationEvents
       //SpringBoot listener contents, used to store listener events, to the corresponding location, these events will be fired one by one
       / / specific content see the previous content: https://blog.csdn.net/qq_34886352/article/details/105188150
		this.earlyApplicationEvents = new LinkedHashSet<>();
	}
Copy the code

The prepareRefresh method actually works the same as the receptionist, arranged as follows:

  • Clock in in the morning, record your time, mute your phone, switch it to active, and get ready to start your day
  • Check the work schedule, due to the adjustment, this period of time is relatively free, all the work is lost to others
  • Roll call, see if all the employees are present, and make sure the required attributes are empty
  • Bring out the new visitor register

Check here to teach you how to use the key attribute, how to add a key attribute Actually very simple also, in the first lesson we learned ApplicationContextInitializer interface, actually add key attribute is his hidden little feature

public class TestInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        // Get the program environment from the context
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        // Set a key property that needs to be defined in the SpringBoot configuration file Application, otherwise an exception will be thrown
        environment.setRequiredProperties("girlFriendName"); }}Copy the code

Strange knowledge increased!

(2) Initialization of BeanFactory

Step 9: Get the Bean factory

protected ConfigurableListableBeanFactory obtainFreshBeanFactory(a) {
    / / the following two methods are implemented by GenericApplicationContext subclass, remember this class view
    // Set the bean factory properties
    / / step 10
    refreshBeanFactory();
    // Get the bean factory
    / / step 11
    return getBeanFactory();
}
Copy the code

This method is relatively simple, and it does two things altogether:

  • Set the serialization ID of the beanFactory
  • To obtain the beanFactory

Step 10: Set the bean factory properties

protected final void refreshBeanFactory(a) throws IllegalStateException {
    // Set the checksum property to true to indicate that the refresh has begun
    // use the CAS technology (compareAndSet), a thread-safe mechanism to prevent locking, compareAndSet the way, through the CPU layer
    // First check if the value is false, if so change to true
    if (!this.refreshed.compareAndSet(false.true)) {
        throw new IllegalStateException(
                "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
    }
    // Set the id used for serialization. Default: application
    this.beanFactory.setSerializationId(getId());
}
Copy the code

Step 11: Get the bean factory

public final ConfigurableListableBeanFactory getBeanFactory(a) {
    / / this method is very simple and direct access to GenericApplicationContext properties, is the following attributes
    // Attribute initialization is done in the constructor, which is very simple
    //private final DefaultListableBeanFactory beanFactory;
    return this.beanFactory;
}
Copy the code

Step 12: Set up the bean, with some AOP-related content in the middle

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // Set the class loader
    beanFactory.setBeanClassLoader(getClassLoader());
    // Sets the expression parser to connect to SpEL expressions that may appear in the configuration file
    beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
    // Set the property editor, used to do the property conversion, binding
    beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

    // Set the bean's backend handler. This is an important mechanism in SpringBoot, and we will focus on the callback method that executes after the bean is created
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    // Set the interfaces to be ignored for autologie. why ignore these interfaces and put them together with the post-processor
    beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
    beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
    beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
    beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

    // Add a parser dependency to the BeanFactory. When the BeanFactory itself needs to be parsed and dependent, it can point to itself
    beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
    // The following three are also the same, when the need to resolve the dependency to refer to itself
    beanFactory.registerResolvableDependency(ResourceLoader.class, this);
    beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
    beanFactory.registerResolvableDependency(ApplicationContext.class, this);

    // Add a post-processor to check whether the bean is a listener
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

    The //containsLocalBean method checks all containers of the bean to see if it contains a bean with a specific name
    //LOAD_TIME_WEAVER_BEAN_NAME: code weaving is aOP-related and will be covered later
    if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
        // Add a post-processor to handle code weaving
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        // Add a zero-hour class loader
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }

    // Register some default bean objects
    // Run the environment's bean object
    if(! beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {// If yes, create a singleton bean
        beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
    }
    // The system property bean object
    if(! beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME,  getEnvironment().getSystemProperties()); }// The system runtime bean object
    if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
        beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
    }
}
Copy the code

To summarize, this seems like a long way to go, but it’s actually pretty dry:

  • Set some properties of the BeanFactory
  • Several important post-processors have been added
  • Set the interface to be ignored for autoloading
  • Some default beans are registered manually

Step 13: this method exists in AnnotationConfigServletWebServerApplicationContext class, is the realization of the subclass, see how the name is processing annotation configuration web service context class

@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // This class is not mature enough. Go! Go find his guardian
    super.postProcessBeanFactory(beanFactory);
    // Whether the base package is set is the scope of scanning annotations
    if (this.basePackages ! =null && this.basePackages.length > 0) {
        this.scanner.scan(this.basePackages);
    }
    // This is also the same, to determine whether to set up the annotated class to scan
    if (!this.annotatedClasses.isEmpty()) {
        this.reader.register(ClassUtils.toClassArray(this.annotatedClasses)); }}Copy the code

Step 14: This method exists in ServletWebServerApplicationContext class, also is the parent class AnnotationConfigServletWebServerApplicationContext class, without annotation configuration information context class

@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // Add a post-processor so that web application beans can get aware to the text
    beanFactory.addBeanPostProcessor(
            new WebApplicationContextServletContextAwareProcessor(this));
    // Autowire ignores objects of type ServletContextAware
    beanFactory.ignoreDependencyInterface(ServletContextAware.class);
}
Copy the code

(3) Use BeanFactory to register the bean definition

First, we need to understand two interfaces, which will help us read the source code later:

  • BeanDefinitionRegistryPostProcessor: Bean definition registry post-processor, which can be used to register and delete bean definitions, At the same time can also modify the implementation method of the bean attribute value postProcessBeanDefinitionRegistry bean definitions (registration) and postProcessBeanFactory method (injection bean properties)
  • BeanFactoryPostProcessor: a bean’s post-processor that modifies the bean’s property values. Implementation method postProcessBeanFactory method (injecting bean properties)

Step 15: Instantiate and invoke the bean factory-registered backend handler, which must be executed sequentially if the order is specified

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    / / getBeanFactoryPostProcessors method, can obtain the bean factory post processor, post processor is added by initialization and listener, specific can point method, and then find the method of adding attributes, watching the method call
    / / initialize the injected class called ConfigurationWarningsApplicationContextInitializer ApplicationContextInitializer interface is achieved, is the first article content we spoke, The working principle of ApplicationContextInitializer interface
    / / listener class called ConfigFileApplicationListener, the contents of the second article, inspect the previous articles
    
    / / have a look at the below invokeBeanFactoryPostProcessors method, this method is very long, more than 100 lines, but it doesn't matter, the principle is very simple, we watch together
    / / step 16
    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

    // It checks for the presence of Aop, and if so, it adds the relevant post-processor for subsequent weaving
    // This is a follow-up Aop related content, which is not discussed here
    if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        beanFactory.setTempClassLoader(newContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); }}Copy the code

Step 16: call the bean factory rear processor parameter description: the beanFactory: used to create the instantiation of the bean factory object beanFactoryPostProcessors: current post processor in this factory for bean plant (strengthen)

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

    //processedBeans hold beans that need to be processed first, objects that implement the PriorityOrdered or Ordered interface,
    // To prevent these objects from being executed repeatedly, the guest officer looks back and explains later
    Set<String> processedBeans = new HashSet<>();
    // Determine whether beanFactory belongs to BeanDefinitionRegistry
    //BeanDefinitionRegistry has the following functions
    //1. Register the bean as a key-value. The key is beanName and the value is beanDefinition.
    //2. Get or remove beanDefiniation according to beanName
    //3. Check whether beanDefinition exists according to beanName
    if (beanFactory instanceof BeanDefinitionRegistry) {
        // Perform type conversion
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
        // Processing is subdivided here
        RegularPostProcessors are used to store normal post-processors
        List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
        //registryProcessors is used to store the bean registration-related processors
        List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
        // Loop the post-processor and categorize them
        for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
            // The way to determine whether to register the associated post-handler for the bean is simple
            / / directly determine whether direct or indirect BeanDefinitionRegistryPostProcessor interface is realized
            if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                // Type the post-processor
                BeanDefinitionRegistryPostProcessor registryProcessor =
                        (BeanDefinitionRegistryPostProcessor) postProcessor;
                / / all realized BeanDefinitionRegistryPostProcessor interface classes, all need to implement postProcessBeanDefinitionRegistry this method
                // When SpringBoot starts at this point, the implementation classes can retrieve the bean-defined registry
                // BeanDefinitionRegistry has all bean definitions according to the previous comments. Add bean objects, delete bean objects in this step
                // This is how the fourth method of configuring beans in Java code works
                registryProcessor.postProcessBeanDefinitionRegistry(registry);
                // categorize into the corresponding collection
                registryProcessors.add(registryProcessor);
            }
            else {
                // In addition to the bean registration related backend handler, is the normal handler, directly through the else classificationregularPostProcessors.add(postProcessor); }}/ / currentRegistryProcessors stored in order of priority in the bean definition registry of post processor
        List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

        // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
        // Get the name of the bean by type from the bean factory
        // First argument: query the type used by beanName
        // The second argument: true: lookup from all beans, false: lookup from singleton beans
        // The third argument: it is easy to understand whether to use the caching mechanism
        String[] postProcessorNames =
                beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true.false);
        // Iterate over the obtained bean to define the backend handler for the registry
        for (String ppName : postProcessorNames) {
            // Checks whether the current rear processor implements the PriorityOrdered interface, and returns true if it does
            // It is necessary to specify the PriorityOrdered interface and Ordered interface
            //PriorityOrdered is a subclass of Ordered, which sets the priority of calls to PriorityOrdered, and always calls the class that implements PriorityOrdered with a higher priority than Ordered
            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                / / the current bean instantiation, and deposit to currentRegistryProcessors getBean method below details
                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                // Add them to processedBeans and process them firstprocessedBeans.add(ppName); }}/ / will currentRegistryProcessors according to priority
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        // Add these bean definition registry afterprocessors to registryProcessors (where all bean registry-related afterprocessors are stored)
        registryProcessors.addAll(currentRegistryProcessors);
        // This method calls the methods of the objects in the collection in turn
        / / forget postProcessBeanDefinitionRegistry method friend, full text search, with detailed explanation
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
        // Finally empty the collection
        currentRegistryProcessors.clear();

        // Get the side Bean definition registry post-processor again
        // The difference is that objects that implement the PriorityOrdered interface are handled instead of objects that implement the Ordered interface
        postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true.false);
        // Here, as above, separate the implementation of the PriorityOrdered and Ordered interfaces
        for (String ppName : postProcessorNames) {
            // Attention!! This time you get an object that implements the Ordered interface
            if(! processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));  processedBeans.add(ppName); }}// Same sort
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        // Add the same, the objects in the collection registryProcessors are already sorted
        registryProcessors.addAll(currentRegistryProcessors);
        / / call postProcessBeanDefinitionRegistry method
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
        / / then empty currentRegistryProcessors
        currentRegistryProcessors.clear();

        / / in the end, some BeanDefinitionRegistryPostProcessor may not achieve PriorityOrdered interfaces or Ordered
        // These objects are called directly through a loop, regardless of the order of execution
        / / when all BeanDefinitionRegistryPostProcessor after the execution, reiterate to false
        boolean reiterate = true;
        while (reiterate) {
            reiterate = false;
             // Get the side Bean definition registry post-processor again
            postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true.false);
            // All loops are judged and executed
            for (String ppName : postProcessorNames) {
                / / processedBeans method initially created collection, used to perform before BeanDefinitionRegistryPostProcessor object
                if(! processedBeans.contains(ppName)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); reiterate =true; }}// It is the same as the one above
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            currentRegistryProcessors.clear();
        }

        // All right!! Here, all BeanDefinitionRegistryPostProcessor object is called
        
        / / the above treatment is BeanDefinitionRegistryPostProcessor interface
        // The BeanFactoryPostProcessor interface is a factoryProcessor interface
        // All that was actually done was the registration logic, and the post-callback to the real bean factory is just beginning
        / / invokeBeanFactoryPostProcessors cycle call postProcessBeanFactory method of collection objects
        // Objects in registryProcessors and regularPostProcessors must implement the BeanFactoryPostProcessor interface
        // The postProcessBeanFactory method must be implemented
        invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
        invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
    }

    else {
        // This else is entered when the bean factory is not BeanDefinitionRegistry
        invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
    }

    // This gets the beanName of the backend processor for all bean factories
    // Why do I get it again? Because when performing BeanDefinitionRegistryPostProcessor is are more likely to sign up for a common bean plant in the post processor
    String[] postProcessorNames =
            beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true.false);

    // store all rear processors that implement the PriorityOrdered interface
    List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
     // Stores all postordered processors that implement the Ordered interface
    List<String> orderedPostProcessorNames = new ArrayList<>();
     // Store a post-processor for which neither interface is implemented
    List<String> nonOrderedPostProcessorNames = new ArrayList<>();
    // Categorize the rear processors
    for (String ppName : postProcessorNames) {
        if (processedBeans.contains(ppName)) {
            //processedBeans holds the BeanName of the post-processor that has been executed, which can be used to determine whether it has been executed
            If yes, skip this step
        }
        else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
            // Separate objects that implement the PriorityOrdered interface, instantiate them, and store them in the corresponding collection
            priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
        }
        else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
            // Separate the objects that implement the Ordered interface and place the BeanName in the corresponding collection
            orderedPostProcessorNames.add(ppName);
        }
        else {
            // The rest are naturally objects that are not implemented by either interfacenonOrderedPostProcessorNames.add(ppName); }}// Same as before! First order
    sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    // Then execute in order, but this time with the postProcessBeanFactory method
    invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

    // Then it is the turn of the object that implements the Ordered interface
    List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
    for (String postProcessorName : orderedPostProcessorNames) {
        orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }
    sortPostProcessors(orderedPostProcessors, beanFactory);
    invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

    // Finally, the object with neither interface implemented
    List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
    for (String postProcessorName : nonOrderedPostProcessorNames) {
        nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }
    invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

    // Clear the metadata cache in the bean factory. The getBean method generates the cache
    beanFactory.clearMetadataCache();
}
Copy the code

To summarize, the long way to do this is to do two things:

  • Call BeanDefinitionRegistryPostProcessor the implementation of the object, the water in the container to add a new bean definition
  • Call the implementation object of the BeanFactoryPostProcessor to add properties to these bean definitions

(4) Bean post-processor

Step 17: Register the bean’s backend handler

protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    / / PostProcessorRegistrationDelegate is used to process the post processor dedicated tools
    // Invoke the registration method step 18
    PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
Copy the code

Step 18: A post-processor parameter review to actually start registering beans! BeanFactory: the bean’s factory class, bean’s container applicationContext: the application’s context, containing the application’s environment information, and so on

public static void registerBeanPostProcessors( ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
    // Get the bean factory's post-processor
    BeanPostProcessor = BeanPostProcessor = BeanPostProcessor
    // Fetch the bean's post-processor from all beanDefinitions
    // So it is not the post-processor that was added earlier with the addBeanPostProcessor method
    // The getBeanNamesForType method returns only the bean name, not the instance object
    String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true.false);

    // Add a unique post-processor BeanPostProcessorChecker
    / / rear BeanPostProcessorChecker is bean processors a detector
    // During the instantiation of a bean, all bean post-handlers are applied to the bean
    // When I say "application", it doesn't have to do anything. The backend processor might find a bean that isn't the target type and skip it
    // But if the post-processor is not working properly on the current bean, the BeanPostProcessorChecker will detect it and flag it
    // We are counting the number of beans, which is one of the conditions to determine the correct operation of the post-processor
    int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
    // Add BeanPostProcessorChecker to the post-processor container
    beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

    // store a post-processor that implements the priorityOrdered interface
    List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
    Deposit / / rear MergedBeanDefinitionPostProcessor type of processor, special post processor
    List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
    // Stores the beanName of the ordered postprocessor that implements the ordered interface
    List<String> orderedPostProcessorNames = new ArrayList<>();
    // Stores the beanName of a postordered processor that does not implement the ordered interface
    List<String> nonOrderedPostProcessorNames = new ArrayList<>();
    // Iterate through all the back processors
    for (String ppName : postProcessorNames) {
        if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
            // post-processor that implements the priorityOrdered interface, enter here
            The handler is instantiated directly
            BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
            // Add the corresponding container
            priorityOrderedPostProcessors.add(pp);
            / / MergedBeanDefinitionPostProcessor is a special processor, he would be to merge the definition of a bean
            if (pp instanceof MergedBeanDefinitionPostProcessor) {
                // Add the corresponding containerinternalPostProcessors.add(pp); }}else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
         // A post-processor that implements the Ordered interface, entering here
            orderedPostProcessorNames.add(ppName);
        }
        else {
            // No postprocessor implements Ordered and priorityOrdered interfacesnonOrderedPostProcessorNames.add(ppName); }}// Sort backend processors that implement the priorityOrdered interface by priority
    sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    / / registered post processor, cycle, add the rear priorityOrderedPostProcessors processor to the rear of the BeanFactory processor in the container
    registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

    / / and then to realize the Ordered the rear of the interface processor, instantiated, and isolated MergedBeanDefinitionPostProcessor
    // Holds an instance object of a postordered processor that implements the ordered interface
    List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
    // Loop through the previously saved beanName
    for (String ppName : orderedPostProcessorNames) {
        // instantiate the post-processor
        BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
        // Store it in a container
        orderedPostProcessors.add(pp);
        / / determine whether for MergedBeanDefinitionPostProcessor (for merger bean definition of special post processor) types of objects
        if (pp instanceof MergedBeanDefinitionPostProcessor) {
            // Add to the corresponding containerinternalPostProcessors.add(pp); }}/ / sorting
    sortPostProcessors(orderedPostProcessors, beanFactory);
    // Will register the afterprocessor with the BeanFactory
    registerBeanPostProcessors(beanFactory, orderedPostProcessors);

    // Now start processing, no postprocessor implements ordered interface nor priorityOrdered interface
    List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
    // Do the basic routine again
    for (String ppName : nonOrderedPostProcessorNames) {
        // instantiate the post-processor
        BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
        // Store it in a container
        nonOrderedPostProcessors.add(pp);
        / / determine whether for MergedBeanDefinitionPostProcessor (for merger bean definition of special post processor) types of objects
        if (pp instanceof MergedBeanDefinitionPostProcessor) {
            // Add to the corresponding containerinternalPostProcessors.add(pp); }}// Register the afterprocessor directly with the BeanFactory without sorting
    registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

    / / the rear handle MergedBeanDefinitionPostProcessor types of processors
    / / to rear MergedBeanDefinitionPostProcessor type of processor for sorting
    sortPostProcessors(internalPostProcessors, beanFactory);
    // Will register the afterprocessor with the BeanFactory
    registerBeanPostProcessors(beanFactory, internalPostProcessors);
    // The post-processor has been sorted and instantiated as required

    // You also need to add a post-processor at the end of all post-processors to find out if the bean is a listener
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
Copy the code

(5) Some extended functions of SpringBoot

Step 19: initialize the messageSource for this context, messageSource is used for internationalization

protected void initMessageSource(a) {
    // Get the BeanFactory
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    // Check whether there is a MessageSource in BeanFactory
    if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
        // Instantiate the bean object of the message source
        this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
        // Determine if there is a multi-layer message source
        if (this.parent ! =null && this.messageSource instanceof HierarchicalMessageSource) {
            / / strong, HierarchicalMessageSource for a multilayer sources
            HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
            if (hms.getParentMessageSource() == null) {
                // If no parent class is set for the message, the parent message source is obtained and assignedhms.setParentMessageSource(getInternalParentMessageSource()); }}if (logger.isTraceEnabled()) {
            logger.trace("Using MessageSource [" + this.messageSource + "]"); }}else {
        // DelegatingMessageSource is basically the utility class that calls the parent message source, if there is no parent message source, nothing is being processed
        DelegatingMessageSource dms = new DelegatingMessageSource();
        // Set the parent message source
        dms.setParentMessageSource(getInternalParentMessageSource());
        // Set the message source
        this.messageSource = dms;
        // Register the singleton bean
        beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
        if (logger.isTraceEnabled()) {
            logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]"); }}}Copy the code

Although the object name inside is very obscure, in fact, just do a national initialization work

Step 20: Initialize the broadcaster

protected void initApplicationEventMulticaster(a) {
    / / get the BeanFactory
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    // Determine whether the bean contains the broadcaster
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
        // Instantiate the broadcaster and assign a value
        this.applicationEventMulticaster =
                beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
        if (logger.isTraceEnabled()) {
            logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]"); }}else {
        // Create a default broadcaster
        this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        // instantiate and assign to BeanFactory
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
        if (logger.isTraceEnabled()) {
            logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
                    "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]"); }}}Copy the code

Step 21: Add the listener implementation to the broadcaster

protected void registerListeners(a) {
    // Get all listeners and add them to the broadcaster
    // Initialize the broadcaster in step 20
    // Listener initialization and registration were explained in great detail in the previous article, but are not covered here
    for(ApplicationListener<? > listener : getApplicationListeners()) { getApplicationEventMulticaster().addApplicationListener(listener); }// Gets the beanName of the listener type bean object, but these objects cannot be instantiated here because we need to let them be processed through the post-processor
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true.false);
    for (String listenerBeanName : listenerBeanNames) {
        // Add it to the container and cache it
        getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    }

    // There is an early broadcast call
    // Since Spring's listener mechanism has not been created before, it is possible that the container has already triggered events that will be cached in earlyApplicationEvents
    // Now the listener is ready to execute the cached event
    // Get earlier events
    Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
    // Clear out the earlier events
    this.earlyApplicationEvents = null;
    // Execute the earlier event you just fetched, which is normally empty
    if(earlyEventsToProcess ! =null) {
        for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
            // Broadcast eventsgetApplicationEventMulticaster().multicastEvent(earlyEvent); }}}Copy the code

Step 22: Clear the cache and send the ContextRefreshedEvent event

protected void finishRefresh(a) {
    // Be aware of the cache in context
    clearResourceCaches();

    // Initialize the lifecycle processing component
    initLifecycleProcessor();

    // Start the lifecycle processing component (lifecycle component)
    getLifecycleProcessor().onRefresh();

    // Broadcast the ContextRefreshedEvent event
    publishEvent(new ContextRefreshedEvent(this));

    // The display view of the bean, which is not the point here, is just an additional feature that is not discussed at the moment
    LiveBeansView.registerApplicationContext(this);
}
Copy the code