Hard Steel Spring Source-50,000 Words Comb Spring Core Principles

Preface

Learn technology, not only to understand the principles, but also to be good at summarizing, but also to learn to apply, only in this way, you can become a true master.

Say nothing but go straight to dry!

Spring Core Interfaces and Classes

The spring framework solves a very critical problem that allows you to manage the relationships between objects in a configuration file instead

  • This is the dependency injection mechanism on which it depends to survive, allowing dependencies between objects to be managed in Spring's IoC container.
  • Manage objects and extra operations by wrapping them in beans.

Bean and BeanDefinition

First Class Citizen of Spring - Bean

  • Bean s are Java objects in nature, but their life cycle is managed by containers.
    Users can define a java class to suit their business needs and tell Spring to manage it in a way that Spring's framework understands, such as configuration files/configuration classes or configuration-related annotations, and he becomes a bean in the Spring container

  • There is no need to add any additional restrictions on the original java class in order to create beans

  • Control over Java objects is configurable

BeanDefinition - Definition of Bean

Generate BeanDefinition to describe Bean based on configuration

Common properties:

  • scope(@Scope)
    • singleton
    • prototype
    • request
    • session
    • globalsession
  • Lazy-loading lazy-init(@Lazy): Determines whether the Bean instance is delayed loading
  • Preferred primary(@Primary): bean s that set true will be the preferred implementation class
  • factory-bean and factory-method(@Configuration and @Bean)

The main thing container initialization does

Configuration information, such as xml or annotations, is first loaded into memory, where the files are treated as Resource objects, then parsed into BeanDefinition instances, and finally registered in the Spring container.

When a container is initialized or a bean instance is first used, the container creates a Bean instance corresponding to BeanDifinition as indicated by these BeanIDifinition instance properties, depending on the Bean creation strategy, whether it loads immediately or delay.

BeanDefinition Source Exploration

Let's look at BeanDefinition and its schema members:

BeanDefinition is an interface, let's look at the source code:

This interface is really in the spring-beans module, which stores the interfaces and classes related to the spring simple container.

BeanDefinition inherits AttributeAccessor and BeanMetadataElement interfaces. Spring provides a wide range of interfaces, each with different capabilities, and a class that implements an interface has a corresponding commitment to have a certain capability.

AttributeAccessor

This interface defines the most basic modification or acquisition of metadata for any object, and is used in BeanDefinition to obtain and manipulate properties of BeanDefinition.

BeanMetadataElement

This interface provides a getSource method to transfer a configurable meta-object, which in BeanDefinition returns the BeanDefinition itself through the getSource method.

For BeanDefinition, the configuration information for a Bean is mainly described to the Spring container.
There are definitions in BeanDefinition for delaying isLazyInit(), getting scope getScope(), and so on.

AbstractBeanDefinition
There are many members of the BeanDefinition family, and I'll just list some of the more common classes.
AbstractBeanDefinition is the base class for the BeanDefinition implementation class

On the basis of AbstractBeanDefinition, Spring derives a series of BeanDefinitions with special uses.

  • RootBeanDefinition
  • GenericBeanDefinition
  • ChildBeanDefinition

RootBeanDefinition can be either a BeanDefinition alone or a parent of other BeanDefinitions, but it cannot be a subclass of other BeanDefinitions.
We can look at its source code:

You can see that once parentName is set in the setParentName method, an exception is thrown.

It should be added here that the inheritance relationship defined in Spring is not inherited by extends or implements, but by setting the parent property in BeanDefinition.


As you can see from the comments in the RootBeanDefinition source code, RootBeanDefinition is typically used to receive information combined by multiple BeanDefinitions at run time.
There is a parent attribute inside the BeanDefinition to represent inheritance, whereas RootBeanDefinition can accept two BeanDefinitions that have an inheritance relationship to accept properties other than parent attributes that are merged together.

Typically, the bean tag in the configuration file is parsed into a RootBeanDefinition.

After Spring 2.5, Spring introduced a GenericBeanDefinition, replacing RootBeanDefinition and ChildBeanDefinition. However, when merging attributes, RootBeanDefinition is used to receive them.

ChildBeanDefinition must depend on a parent BeanDefinition, which cannot exist alone, but has been completely replaced by GenericBeanDefinition and does not require learning.

GenericBeanDefinition

GenericBeanDefinition is a new Bean File Definition configuration class added after Spring 2.5 and is a better alternative to RootBeanDefinition and ChildBeanDefinition.

In addition to other BeanDefinition features, it also has the parentName attribute, which makes it easy for programs to set parentBeanDefinition at run time.

SpringIoc Container

The SpringIoc container is a container that manages beans and, in Spring's definition, requires that all IOC containers implement the interface Bean Factory

BeanFactory

BeanFactory, located under the package org.springframework.beans.factory, is a top-level container interface

Under this interface, a FACTORY_is defined BEAN_ PREFIX variable, which is used primarily to get an instance of FactoryBean.

Notice that FactoryBean and BeanFactory are two completely different things.

Differences between BeanFactory and FactoryBean

BeanFactory
BeanFactory is the root interface of the Spring container that defines the most fundamental functional features of the Bean Factory. For example, an Object getBean(String name) retrieves a bean instance from a container based on the bean name, and so on.

BeanFactory is a container for managing beans, and Spring generates beans that are managed by BeanFactory's implementation classes.

FactoryBean
Factory Bean is also an interface that allows users of T getObject() to generate beans using a more complex set of logic.

FactoryBean is also a Bean in nature, but this Bean is not used to inject into other places to use it. Instead, it is used to generate some ordinary beans. When this interface is implemented, the spring container will initially take out the beans that implement this interface and use the getObject method inside the Bean to generate the beans we want. Of course, business logic that generates beans is also written in the getObject method.

BeanFactory Architecture

Next, let's look at the architecture of BeanFactory:


BeanFactory has a large inheritance and implementation system, and has many subinterfaces and implementation classes. Each interface and implementation class has its own occasion. Interfaces mainly describe that containers have certain functions, while implementation classes implement these functions.

Spring's Ioc is divided into two main routes, one is a simple container based on BeanFactory and the other is an advanced container based on ApplicationContext.

ApplicationContext Application Context Advanced Container is also a widely used type. Compared to BeanFactory, Advanced Container adds a lot of practical application-oriented functionality, which simplifies the functionality originally implemented by encoding in BeanFactory to configuration.

According to the single principle of program design, in fact, each of the top-level interfaces is a single responsibility, providing only one aspect of functionality.

ListableBeanFactory

The method of this interface can provide information about beans in the form of lists. The most important feature of this interface is that it can batch list instance information of factory production.

Let's take a general look at how this interface works:

int getBeanDefinitionCount(); //Get the total number of BeanDefinition s
String[] getBeanDefinitionNames(); //Gets an array list of BeanDefinition names
String[] getBeanNamesForType(ResolvableType type);//Get all Bean names by specifying the type
//....

AutowireCapableBeanFactory

Let's first add two terms:

  • Component Scan: Automatically discover beans that need to be created in the application container
  • Auto-assembly: Automatically satisfy dependencies between beans

The logic for @Autowired auto-assembly in spring is dependent injection through the Object resolveDependency() method of the interface

Five assembly strategies are defined in this interface

Where AUTOWIRE_AUTODETECT has been discarded in Spring 3.0.

int AUTOWIRE_NO = 0; //No auto-assembly
int AUTOWIRE_BY_NAME = 1; //Auto-assemble by name
int AUTOWIRE_BY_TYPE = 2; //Auto-assembly by type
int AUTOWIRE_CONSTRUCTOR = 3; //Automatically assemble according to constructor

For @Autowired tags, the auto-assembly strategy is AUTOWIRE_BY_TYPE Auto-assembly by Type

DefaultListableBeanFactory

DefaultListableBeanFactory is a truly stand-alone IOC container that inherits the abstract class AbstractAutowireCapableBeanFactory and, most importantly, implements BeanDefinitionRegistry at the same time.
BeanDefinitionRegistry is the registration interface for BeanDefinition.

DefaultListableBeanFactory has one of the most important member variables:

private final Map<String, BeanDefinition> beanDefinitonMap = new ConcurrentHashMap<>(256);

This member variable is the carrier used to store all registered BeanDefinition instances in the container.
In addition, this member variable is defined in the SimpleBeanDefinitionRegistry, but here it only provides registry functionality, not factory functionality.

Therefore, the beanDefinitonMap in DefaultListableBeanFactory is important.

Since it is a private member variable, you need to call the method provided by DefaultListableBeanFactory to manipulate the BeanDefinition's vector.

ApplicationContext

Next, let's look at a more complex family of containers, most typically the ApplicationContext interface.

The Spring Advanced Container implements the ApplicationContext interface
To distinguish them from simple containers, advanced containers are often called contexts, or contexts.

So when you hear context, it's often what containers mean, but there's just so much extra functionality besides creating beans that users can use out of the box to suit their needs. This is different from our previous Bean Factory factory.

When we use the SpringIoc container, the vast majority of the classes we come into contact with are implementation classes of the ApplicationContext interface.

BeanFactory is Spring's infrastructure for the Spring framework itself, while ApplicationContext is for developers who use the Spring framework.

We can see that the ApplicationContext is called an advanced container because it has more functionality than BeanFactory because it inherits multiple interfaces.

First we see that it inherits the EnvironmentCapable interface

public interface EnvironmentCapable {

	/**
	 * Return the {@link Environment} associated with this component.
	 */
	Environment getEnvironment();

}

Inside this interface, we see that there is only one getEnvironment() method, which is mainly used to get the Environment.

The truth is to get some startup parameters.

He also inherits the Listable Bean Factory interface, which allows him to manage beans as a list

The Hierarchical Bean Factory interface is also implemented to support multilevel containers for the management of each layer of beans

In addition, it inherits many interfaces from MessageSource, ApplicationEventPublisher, ResourcePatternResolver

They can be used to manage some messages, internationalize, publish events, and load resource files.

The ApplicationContext container handles events through the ApplicationEvent class and the ApplicationListener interface. If a Bean implementing the ApplicationListener interface is registered with the container, every time we publish an ApplicationEvent through the ApplicationContext, it is notified to the registered Lieuter

This is the standard observer designer pattern

Common containers for ApplicationContext

Classic containers for traditional XML-based configurations:

  • FileSystemXmlApplicationContext: Load configuration from file system
  • ClassPathXmlApplicationContext: Load configuration from classpath
  • XmlWebApplicationContext: Container for Web applications

Currently more popular containers:

  • AnnotationConfigServletWebServerApplicationContext
  • AnnotationConfigReactiveWebServerApplicationContext
  • AnnotationConfigApplicationContext

They all have the general functionality of refresh()

  • Container Initialization, Configuration Resolution
  • Registration and activation of BeanFactoryPostProcessor and BeanPostProcessor
  • Internationalized Configuration
  • ......

Back in the ApplicationContext, we can see that the methods inside it are read-only, that is, they all start with get, that is, they only provide get operations:

So we need a subinterface to provide configurable capabilities to the Application, which is
ConfigrableApplicationContext:

It inherits the Lifecycle interface and enters it:

This interface provides methods such as stop, start for life cycle management.

ConfigrableApplicationContext mainly provides refresh and close methods with the ability to start refresh and close the application context, and here the refresh method is what the main implementation containers of the ApplicationContext mentioned earlier need to do.

With the ApplicationContext closed, refresh can restart the container
On startup, calling refresh also clears the cache and reloads the configuration information
The implementation is in the AbstractApplicationContext abstract class that implements the interface.

AbstractApplicationContext

AbstractApplicationContext implements opening to extensions and modifying closed design principles, that is, opening and closing principles, by combining a number of easily changing function logic and proxying some of its member variables, and finally using the template method pattern, allowing subclasses to provide some support for functions for the parent class or setting substitution for the parent member variables. Provides flexible and scalable architecture support for the Spring Framework.

The refresh method is the best implementation of the template method pattern.

Resource

In java, resources can be abstracted into URLs, and we can parse the protocols in Url to handle the operation logic of different resources.

Spring abstracts how physical resources are accessed into resources


Basic operations on resources are defined in this interface. The Resource interface inherits the InputStreamSource interface

InputStreamSource only provides the getInputStream() method, which returns an InputStream instance, a resource flow.

Spring provides a powerful way to load resources:

  • Automatically identify resource address prefixes such as "classpath", "file:"
  • Support automatic resolution of Ant-style wildcard resource addresses

ResourceLoader

ResourceLoader is used to implement different Resource loading policies and return a specific type of Resource as needed.

refresh method

Let's take a look at the AbstractApplicationContext#refresh method next.
Before we go into this approach, let's get some core knowledge

PostProcessor Post Processor

Various PostProcessor s are available in the Spring framework as post processors for containers or beans

These PostProcessor s are also Bean s that need to be registered in containers.

  • The methods inside are called by the container at a specific time.
  • Implement Bean Extension without Changing Container or Bean Core Logic
  • Wrap beans, influence their behavior, and modify their content

Types of PostProcessor s

It is roughly divided into container-level post-processors and Bean-level post-processors

  • BeanDefinitionRegistryPostProcessor
  • BeanFactoryPostProcessor
  • BeanPostProcessor

The first two are container-level postprocessors, and the last one is Bean-level postprocessors.

BeanDefinitionRegistryPostProcessor


From the comment documentation, we can see that BeanDefinition RegistryPostProcessor allows more custom BeanDefinitions to be registered before normal BeanFactoryPostProcessor detection begins.

Looking at the source code, we can see that this interface inherits from BeanFactoryPostProcessor.

Only one method is provided:

This method receives the registry parameter, so just look at the method declaration information to see that we need to create an instance of BeanDefinition inside the method body and register our BeanDefinition inside the registry by passing in the registry

Let's take a look at the source code for BeanFactoryPostProcessor:
It affects containers through postProcessBeanFactory.

BeanPostProcessor


For each Bean instance created by a container, the postprocessor obtains callback execution from the container before calling the container initialization and after any Bean initialization callback.

Let's take an example:

/**
 * Created By Little Flydragon
 */
@Configuration
public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(beanName+"Called postProcessBeforeInitialization Method");
        return bean;
    }

	@Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(beanName+"Called postProcessAfterInitialization Method");
        return bean;
    }
}

We implement BeanPostProcessor by ourselves, then implement its postProcessBeforeInitialization and postProcessAfterInitialization methods.
Then start the project:

After execution, we can see that both methods are executed for each Bean, and postProcessBeforeInitialization is executed before postProcessAfterInitialization.

Seeing if this is a flash of inspiration, can we wrap beans using Bean PostProcessor's ability to wrap beans, that is, once they are created, put a common logic on their packaging inside postProcessAfterInitialization, such as logging time-consuming statistics, enhancing behavior, and returning beans? This again involves the scope of AOP.

Let's start with PostProcessor, which mainly concerns the container's post-processor and Bean's post-processor. The framework itself also provides many implementation classes for PostProcessor. Each PostProcessor implementation class is for different scenario requirements. Spring applies these different implementation classes to complete the framework's own tasks. Mainly during container startup and bean acquisition. We can also implement Processor on our own to extend its capabilities.

Aware

In order to facilitate the successful acquisition of subsequent knowledge, let's learn another important interface Aware

Previously, we learned that containers are basically non-intrusive to the Bean's logic, so Beans generally do not need to know the state of containers or use containers directly, but in some cases they need to operate directly on containers in Beans, at which point you need to set the perception of containers in Beans, which is what Aware does.

As we can see from Aware, there is no method but to use it as a label, so what Aware can do directly in Spring is to inherit its own subinterface from the Aware interface.

Common Aware subinterfaces are as follows:

  • ApplicationContextAware
  • MessageSourceAware
  • ApplicationEventPublisherAware
  • BeanFactoryAware
  • ResourceLoaderAware
  • BeanNameAware

ApplicationContextAware


Inside this interface we can see that it defines a method for setApplicationContext.
This method allows the Bean implementing the interface to pass in an instance of the container itself as a parameter to the Bean when it creates the Bean instance.

BeanNameAware

Let's look at the next subinterface, BeanNameAware:

In this interface we can also see that only one method, setBeanName, is defined
The purpose of this method is to pass in the name of the Bean for use by the implementation class of the interface

BeanFactoryAware

Mainly used to get the current BeanFactory so that the container's services can be invoked

MessageSourceAware

Mainly used to obtain text information about MessageSource

ApplicationEventPublisherAware

Primarily used to obtain publisher instances to publish events

ResourceLoadAware

The main purpose is to get the resource loader, through which we can get external resource files

Let's demonstrate through the code:

/**
 * Created By Little Flydragon
 */
@RestController
public class TestController implements ApplicationContextAware, BeanNameAware {
    private String myName;
    @Autowired
    private ApplicationContext myContainer;
    
    @GetMapping("/getMyName")
    public String  handleRequest(){
        System.out.println("I am:"+myName);

        String[] names = myContainer.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println("Get registered to container BeanDefinition Name:"+name);
        }
        return "OK";
    }

    @Override
    public void setBeanName(String name) {
        this.myName = name;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

    }
}

Once you've finished writing, start the project and open Postman to test it:

After testing, we found that we can really get the resources we want, and it is worth noting that if we want to get container resources, we must register them as container managed beans in addition to implementing the Aware interface.

Spring Event Notification Mechanism

Event listener mode

The listener listens for interesting events and responds to them as soon as they occur. The event listener consists of three components:

  • Event Source
  • Event Listener
  • Event Object

We'll show you through the code:

1. Create Events

@Data
public class Event {
    private String type;
}

2. Create an event listener interface

public interface EventListener {
    void processEvent(Event event);
}

3. Create a specific event listener to implement EventListener

public class SingleClickEventListener implements EventListener{
    @Override
    public void processEvent(Event event) {
        if ("single".equals(event.getType())){
            System.out.println("Single machine event triggered...");
        }
    }
}
public class DoubleClickEventListener implements EventListener{
    @Override
    public void processEvent(Event event) {
        if ("double".equals(event.getType())){
            System.out.println("Double-click event triggered...");
        }
    }
}

4. Create Event Source

public class EventSource {
    private List<EventListener> listenerList = Lists.newArrayList();


    public void register(EventListener listener){
        listenerList.add(listener);
    }

    public void publishEvent(Event event) {
        for (EventListener listener : listenerList) {
            listener.processEvent(event);
        }
    }
}

5. Create main function to test

public static void main(String[] args) {
        EventSource eventSource = new EventSource();
        SingleClickEventListener singleClickEventListener = new SingleClickEventListener();
        DoubleClickEventListener doubleClickEventListener = new DoubleClickEventListener();
        Event event = new Event();
        event.setType("double");

        //Register Time Monitor
        eventSource.register(singleClickEventListener);
        eventSource.register(doubleClickEventListener);

        //Publish Events
        eventSource.publishEvent(event);
    }


After testing, we found that the event source broadcast a double-click event to all registered listeners, but only listeners interested in the event responded to the event.
This is the general implementation of the event listener mode, which is actually an implementation of the observer mode of the classic design mode.

Spring Event Driven Model

There are three components of an event-driven model:

  • Event: ApplicationEvent abstract class

    • ContextStoppedEvent: Event triggered after the container has stopped
    • ContextRefreshedEvent: Event triggered after container initialization or refresh is complete
    • ContextCloseEvent: Event triggered after the container is closed
    • ContextStartedEvent: Event triggered after the container starts
  • Event listener: ApplicationListener

  • Event Publisher

    • ApplicationEventPublisher
    • ApplicationEventMulticaster
Event

Let's first look at the Application Event source code:

We find that within the constructor of this abstract class, an Object-type parameter is accepted, and source refers to the event source.

Events prior to Spring 4.2 must inherit ApplicationEvents, whereas the framework has provided a PayloadApplicationEvent since 4.2:

It is a subclass of ApplicationEvent because it is a generic class and can be packaged with any type. Events are no longer forced to inherit ApplicationEvents. Once we send an event of any type inside the container, the event object PayloadApplicationEvent is automatically wrapped inside the frame.

Event listener


The listeners in Spring inherit EventListener, so let's look at the source code for the ApplicationListener:

You can see that there is only onApplicationEvent in the ApplicationListener, which accepts the parameter ApplicationEvent, which is used to process events.

Spring also defines two subinterfaces of the ApplicationListener that provide the ability to filter events.
Both SmartApplicationListener and GenericApplicationListener inherit the Ordered interface and have the ability to sort by giving listeners a priority from small to large to ensure the order of execution.


As we can see from the source code, GenericApplicationListener filters events using ResolvableType, a tool added after Spring 4.0 to obtain generic information, which can be used to get information about incoming generics, similar to the reflection mechanism.

Event Publisher

Event publishers are mainly designed with interfaces

  • ApplicationEventPublisher
  • ApplicationEventMulticaster

Using these two interfaces, our service is capable of event publishing.

ApplicationEventPublisher

Does it feel a little familiar to see this interface?

We found that the ApplicationContext implements the ApplicationEventPublisher, which also indicates that the ApplicationContext has the ability to publish events.

Since we have an Application Event Publisher, why do we need an Application Event Multicaster?
Let's first look at the source code for the Application Event Publisher:

As you can see, there are only two methods in it, both of which are related to publishing events, that is, our interface can only be used to publish events.

ApplicationEventMulticaster

With this in mind, as we learned earlier, the event source should have a place to register Linstener, let's take a look at the source code for the ApplicationEventMulticaster:

From the source code, we can see that there is no inheritance relationship between the two interfaces, but the ApplicationEventMulticaster has methods to add and remove ApplicationListener s, as well as methods to publish events.

Let's take a look at the main members of the ApplicationEventMulticaster:

You can see that an abstract class of AbstractApplicationEventMulticaster is set in Spring as the default implementation of ApplicationEventMulticaster.
In the source code, let's have a look:

In the source code, we can see that it has a private member variable. As you can see from the name, it is used to save the registered Listener. Click in to see:
You can see that there is indeed an ApplicationListener of Set type, which is used to receive the applicationListeners, because our applicationListeners are also some Beans, so the next collection is the Bean names that specifically hold these Listeners.

Because AbstractApplicationEventMulticaster is only an abstract class, the default impleApplicationEventMulticaster implementation will be used if there is no local implementation of AbstractApplicationEventMulticaster.

In the source code, we find that it has a taskExecutor member variable, which is an executor, which means it supports multithreaded methods of handling listeners.
Let's take a look at this approach:

	@Override
	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
		for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
			Executor executor = getTaskExecutor();
			if (executor != null) {
				executor.execute(() -> invokeListener(listener, event));
			}
			else {
				invokeListener(listener, event);
			}
		}
	}

From this method, we can see that it supports two modes. If executor is not empty, it will handle events asynchronously in a multi-threaded way. If executor is not set, it will execute listener s one by one in a synchronous way.

Why not use the ApplicationEventMulticaster directly instead of the ApplicationEventPublisher

From a designer's point of view, it's easy to understand, for example, that Bean s and containers themselves only want to publish an event, not maintain event listeners, so Spring further splits the event source, abstracts the event publisher interface, and then proxies ApplicationEventMulticaster. Let the implementation class of the ApplicationEventPublisher implement the logic within the publishEvent.

The main purpose of publishEvent is to publish events by calling the multicastEvent method of the ApplicationEventMulticaster implementation class.

Attack refresh method, hand tear container refresh logic

Now that the defenses around the containers have been conquered one after another, let's begin to attack the logic of initializing the containers. Attacks the refresh method of AbstractApplicationContext, which is common to all types of advanced containers.

The main function is to refresh the Spring container, which means to empty the BeanFactory from its initial state and then fill the various bean instances as shown below.

refresh is also a common point for interviewing the Spring framework, so we must study hard.


When we're done, we break the first line of refresh and start the container:

This synchronized step primarily adds a synchronization lock to the container to prevent other threads from initializing or destroying the container while it is in the refresh phase

Next you will enter the prepareRefresh() method, which is primarily used to prepare the refresh container.
The main things you do in this approach are

	protected void prepareRefresh() {
        // Switch to active.
        //Set the current time, which is the container start time, to facilitate subsequent logging, as well as some statistical work performed by the container
        this.startupDate = System.currentTimeMillis();
        //Set Non-Closed State
        this.closed.set(false);
        //Set to Activated
        this.active.set(true);
        //Configure Log Level
        if (logger.isDebugEnabled()) {
            if (logger.isTraceEnabled()) {
                logger.trace("Refreshing " + this);
            } else {
                logger.debug("Refreshing " + getDisplayName());
            }
        }
        //Initialize the propertySource property of the environment (Evironment)
        //Example: <context:property-placeholder location="classpath*:/config/load.properties"/>
        initPropertySources();

        //Verify that requiredProperties for Environment exist
        getEnvironment().validateRequiredProperties();

        //See if some listeners are loaded when the container starts, earlyApplicationListeners is null by default
        if (this.earlyApplicationListeners == null) {
            this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
        } else {
            this.applicationListeners.clear();
            this.applicationListeners.addAll(this.earlyApplicationListeners);
        }
        //Create Event Collection
        this.earlyApplicationEvents = new LinkedHashSet<>();
    }

Next you enter the obtainFreshBeanFactory method:

This step mainly involves the registration of BeanDefinition
This step is important for xml configuration, but for annotations, it is simply a call to the refreshBeanFactory of a subclass
Here we go:

Enter refreshBeanFactory:

For annotations, it is actually the refreshBeanFactory method inside the GenericApplicationContext that is called
The call to refreshBeanFactory in the xml configuration is used to generate an instance of the DefaultListableBeanFactory internal container, and then register the BeanDefinition with the DefaultListableBeanFactory internal container instance. For the comment we're using here, DefaultListableBeanFactory is created when the container's constructor is called.

So the main purpose here is to update the refresh status of the AnnotationApplicationContext instance, while setting the serializationId on its internal DefaultListableBeanFactory to facilitate external serialization over the network to get the exclusive DefaultListableBeanFactory instance here

Let's look at the prepareBeanFactory method again

At this point we have accepted the DefaultListableBeanFactory instance.
Enter into the prepareBeanFactory method:

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		// Tell the internal bean factory to use the context's class loader etc.
		//Tell the internal Bean factory to use the container's class loader
		beanFactory.setBeanClassLoader(getClassLoader());
		//By setting up the BeanFactory's Expression Language Processor, Spring3 has started to add support for language expressions, and by default #{bean.xxx} can be used to get instance values inside beans
		beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
		//Add a default ropertyEditor for beanFactory
		beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

		//Add a postprocessor to inject the ApplicationContext object when the application-defined Bean implements the ApplicationContextAware interface
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

		//If a Bean relies on an implementation class for an interface, they are ignored during auto-assembly
		//Spring notifies other ways to handle these dependencies
		beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
		beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
		beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
		beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

		//Fix dependencies, here are special rules for registering auto-assembly, such as an implementation class for the BeanFactory class interface that is specified as the current BeanFactory at run time
		beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
		beanFactory.registerResolvableDependency(ResourceLoader.class, this);
		beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
		beanFactory.registerResolvableDependency(ApplicationContext.class, this);

		//Register an early postprocessor to detect internal bean s as listeners for applications
		//The purpose of the ApplicationListenerDetector is to determine if a Bean is an ApplicationListener
		//If so, join the event listener queue
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

		// If a LoadTimeWeaver is found, then the post-processor will be prepared to "weave" into the bean factory
		if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			// Setting up temporary class loaders for type matching
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}

		// Register default environment bean s
		if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
		}
	}

Now that we've finished, let's go back to the refresh method and go into the postProcessBeanFactory method.

This method is a hook method used to allow containers to register the necessary postProcess.
The hook method is either implemented or not by subclasses
Follow up:

We will find that PostProcessor does not need to register subclasses for this container

Continuing, you're in the invokeBeanFactoryPostProcessors method

The primary purpose of this method is to register container-level PostProcessor

As we proceed, we come to the registerBeanPostProcessors method

The Bean-level postprocessor comes after the container-level postprocessor is completed.

This step of registerBeanPostProcessors is to register the previously defined bean-level post-processors into containers so that they can be triggered at specific stages to perform specific logic when the getBean method is subsequently called to create Bean instances.

With this Bean-level postprocessor, it is easy for us to refine and customize Beans.

Next you enter the initMessageSource method

Here are some international configurations, the main purpose is to show different language content for different regions.

Continue executing and enter initApplicationEventMulticaster()
This method initializes the event publisher, which receives different events from classes that implement the Application EventPublisher interface and distributes them to different event listeners for processing.

The first thing we see when going into this method is that it first determines if the container has previously registered a custom event publisher and if it is directly useful.
Otherwise, the default SimpleApplicationEventMulticaster will be used as the event publisher.

We can see that SimpleApplicationEventMulticaster was created to support event publishing.
Once we've done this, we've created the SimpleApplicationEventMulticaster.

Next, the onRefresh() method is executed

This method is also a hook method, primarily reserved for its subclasses, to initialize other special beans, which occurs before the finishBeanFactoryInitialization method in the refresh method, which occurs before the instantiation of a single Bean.
The onRefresh method is commonly used on some Web containers

Continue execution


This method is to register a listener with our previous ApplicationEventMulticaster to listen for different events, since events and event publishers alone do not form a complete event monitoring mechanism, they are complete.

Continue to the finishBeanFactoryInitialization method

Enter this method:

We will find that this method first determines if there is an automatic type converter ConversionService in the container, and if there is one, getBean will get a Bean instance from the container that provides a type conversion. The so-called type converter is to convert the property value to the corresponding type when assigning a value to the Bean instance from the container.

Only some type conversions that are not supported by the Spring container itself need to be handled by these converters.

Go down again:

The purpose of this step is to register default parsers in the network container that can parse values in the configuration file and inject them into the ${} expression that is marked with the @Value comment or configured inside the Xml.

Continue to the following:

// Stop using temporary class loaders for type matching
beanFactory.setTempClassLoader(null);

Then stop using the temporary class loader, because aop's operation is complete and there is no need to use the temporary class loader to load the jvm-generated proxy class
Execute further:

// Allow caching of all bean definition metadata without further changes
beanFactory.freezeConfiguration();

This step is primarily used to freeze container-related configurations, which makes previously refreshed content stored in memory reliable and stable

Look at the next step

// Instantiate all remaining (non-lazy-init non-delay loaded) singletons
   beanFactory.preInstantiateSingletons();

This step is to instantiate all remaining bean instances whose default scope s are not delayed loads as singleton s

For Spring Advanced Containers, the default beans are singleton s and are not lazily loaded, so the corresponding bean instances are created and managed here

Follow up and we'll see that it goes into the DefaultListableBeanFactory class

Skip the log and let's look at the following logic:

First iterate through the name of the registered BeanDefinition, then use that name to go through the corresponding BeanDefinition instance in the past

RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);

Here, the RootBeanDefinition accepts the combined BeanDefinition, getMergedLocalBeanDefinition, which has a deep level of call and is more faint to analyze, so we just need to remember its role.

MergedLocalBeanDefinition is designed to be compatible with a variety of BeanDefinitions.

Different beans instantiate a GenericBeanDefinition when loading a SpringBean definition, which can be converted directly to a RootBeanDefinition, so this is fine for normal BeanDefinitions

In another case, he also supports ChildBeanDefinition, which has an inheritance relationship. His parent specifies another BeanDefinition, which combines ChildBeanDefinition and parent BeanDefinition attributes together or converts them to RootBeanDefinition and returns them. So in order to be compatible with the original ChildBeanDefinition, it makes sense to use RootBeanDifition here.

if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
       if (isFactoryBean(beanName)) {
				Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
				if (bean instanceof FactoryBean) {
					final FactoryBean<?> factory = (FactoryBean<?>) bean;
					boolean isEagerInit;
					if (System.getSecurityManager() != null 
                           && factory instanceof SmartFactoryBean) {
						isEagerInit = AccessController
                               .doPrivileged((PrivilegedAction<Boolean>)
										((SmartFactoryBean<?>) factory)::isEagerInit,
								getAccessControlContext());
					}

Then, judging here, first the BeanDefinition instance is not abstract, is singleton, and is not lazily loaded.

If all are satisfied, instantiation begins

Then decide if the bean is a FactoryBean, and if so, go to the container to get the FactoryBean instance.

If the Beans inside FactoryBean are delayed loaded, isEagerInit if they are not, and getAccessControlContext() if the associated creation method has access, then the Beans inside FactoryBean are created through getBean s.


There's a SmartFactoryBean involved, so let's look at this interface.


It can set whether instances are delayed or non-delayed.

Spring Dependent Injection

In order to control the life cycle of a Bean, Spring also considers that it is possible for itself or the user to customize the behavior inside the Bean at each stage of its instantiation, so the entire output process is particularly complex.
There are thousands of lines of light-core code, and if you go into the details, you'll be absolutely dizzy.
But it works a lot better if you just grab the skeleton to understand the core part, so we'll find it clearer and clearer by first understanding the veins and then learning the details.

In the refresh method in AbstractApplicationContext:

//Instantiate all remaining (non-lazy-init non-delayed) singletons
beanFactory.preInstantiateSingletons();

Instances of beans that are not lazily loaded are initialized in this method, and beans managed by default in our ApplicationContext container are singleton s and are not lazily loaded.
So if no bean s are specifically set, the getBean method is called at this step to instantiate them.
So the getBean method here is the focus of our next research, and dependent injection is also done here.

There are many ways to rely on injection, and we focus on injecting according to @Autowired.

Here's another reminder for Xiaobian. It relies on deep levels of injection nesting and jumps in several classes. If hard steel knows the details inside, don't mention everybody. Xiaobian is already halo.

Therefore, we must change our thinking. Since the difficulty is too great, we can only break through one by one by grasping the key points, not reluctant to fight and understanding the whole situation.
So we're also going to open the National Map to fight:

This route is based on @Autowired injection and parsing.

We can attack each module one by one from top to bottom. The so-called attack is not to understand all the details, every line of code, but to understand its general function.

Our goal is clear, mainly to understand the implementation of dependency injection, in order to minimize learning costs and maximize learning results.

After just cracking down on the source code in the brain map, we can see that from top to bottom is a continuous and in-depth process.
Next, let's get a general idea of what each module will do.

First, AbstractBeanFactory, an abstract class, provides a way to get an instance of a bean, which involves a different process based on different scope s.

This article mainly studies singleton, so we mainly look at the DefaultSingletonRegistry class. By name, we know that he is the default implementation class registered for a singleton bean, which provides the getSingleton method to get a singleton instance.

````getSingleton```This method attempts to get a Bean instance from a three-tier cache, and the reason for differentiating into a three-tier cache is primarily to solve the problem of circular dependency.

If no Bean instance is found in the cache, the container will be created, so you will come to the AbstractAutowireCapableBeanFactory, which calls the createBean method to do some preparatory work before it is created, and then calls doCreateBean to create the Bean instance.

It is not possible to create a Bean instance inside a doCreateBean, but also to see if the properties inside the bean instance are tagged with dependency injection tags such as @Autowired or @Value, and if so, tags associated with them. Our applyMergedBeanDefinitionPostProcessors are mainly used to post-process the merged BeanDefinition, which also involves the processing of related logic.

After tagging, the Bean's member variables are considered for assignment, so dependency injection is done inside the populateBean.

Our assault forces will only hit this level.

Later, he will post-process the properties by AutowiredAnnotationBeanPostProcessor's postProcessProperties method to implement @Autowired's injection logic, and step-by-step to DefaultListableBeanFactory to resolve the dependencies, mainly because BeanDefinition is stored here. By looking at BeanDefinition, we can find the dependencies between beans.

Once a dependency is found, the service provided in the DependencyDescriptor class is invoked for injection.

That's the whole injection-dependent process. Here's just a general outline, but it's far from that simple.

doGetBean


Here we focus on the getBean method, and what really works in the getBean method is the doGetBean method. Let's see what this method does:

  1. First, he tries to get a single Bean instance from the container's cache. This single Bean may be a Bean or FactoryBean instance itself. If it is a Bean, it returns directly. If it is a FactoryBean, it returns a bean instance through the getObject method. If you can't get it at this point, you need to let the container create the beans.
  2. Next comes the logic for determining circular dependency, which is why third-level caches are used.
  3. If the BeanDefinition instance of the bean is not registered in the current container, it will recursively go to the parent container to find it
  4. If the BeanDefinition of the bean is in the current container, get its instance from the container.
  5. Recursively instantiate an explicitly dependent bean Explicitly by setting a deoends-on to the bean
  6. Create Bean Instances with Different Strategies for Different scope s
  7. Type Check Bean s

With these macro-understanding, it is not difficult to crack this part of the code, we directly open the city gate to meet!

Code to directly open the doGetBean method of AbstractBeanFactory
First line:

The first line is to convert the name of this bean passed in by a getBean into a real beanName in the container, because the name passed in may be the name of the bean itself or the name of a FactoryBean with the &symbol, or it may be an alias passed in, so we will convert it all into a beanName.

Once you get the beanName, you move on to the next line of code.

//Try to get a complete Bean from the first level cache
Object sharedInstance = getSingleton(beanName);

Enter this method:

We can see that it calls an overloaded method, and the second parameter, allowEarlyReference, is true, allowing non-delayed loading, that is, immediate loading. We enter the method.

	@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		//Try to get a complete Bean from the first level cache
		Object singletonObject = this.singletonObjects.get(beanName);
		//If a complete Bean has not been created, the name of the bean being created is saved in singletonsCurrentlyInCreation
		//So see if you're creating one
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			//Attempt to lock first-level objects, since the next step is to manipulate cached objects
			synchronized (this.singletonObjects) {
				//Attempt to retrieve from the second-level cache earlySingletonObject, which stores Bean instance caches that have not yet had an attribute addition operation
				singletonObject = this.earlySingletonObjects.get(beanName);
				//If the secondary cache has not been fetched and the second parameter is true, true means that the bean is allowed to be referenced circularly
				if (singletonObject == null && allowEarlyReference) {
					//Attempting to get a single factory instance that created this Bean from the cache of the third-level cache singletonFactories, an ObjectFactory instance
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					//If a factory instance is obtained
					if (singletonFactory != null) {
						//Call the factory's getObejct method to return an object instance
						singletonObject = singletonFactory.getObject();
						//Put instances in a secondary cache
						this.earlySingletonObjects.put(beanName, singletonObject);
						//Remove from Level 3 Cache
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

First, he tries to get a single instance corresponding to a beanName from a ConcurrentHashMap of singletonObjects, where singletonObjects are the first level cache of a single cache. A single bean instance that is primarily used to preserve the final shape.

So since we are calling the container's getBean for the first time to create a non-delayed loaded instance ahead of time, we can't find it in the and cache. This leads to the if statement below, which essentially ensures that the bean instance is not available from the first level cache and that it is the instance being created.
Let's go into if and see this isSinglesonCurrentlyInCreation method:

This step is primarily to find out if there is a beanName in the list of single beans being created to solve the problem of circular dependency.

Then in the if logic below, first add a synchronization lock to the first level cache object to manipulate the subsequent cache to prevent threads from concurrently operating on the cache.

After locking, earlySingletonObjects has locked singletonObjects, a first-level cache that supports multithreaded operations, so operations on other caches are thread-safe and synchronized. To improve performance, the other two caches are using HashMap

earlySingletonObjects is a Bean that has not yet called the populateBean method to assign a value to a property

If it is obtained at this step, it will be returned directly, if it is not, and allowEarlyReference is true, it will go into if and try to get it from another cache, singletonFactories, which is the third layer cache, where the corresponding ObjectFactory instance of Bean is stored. We can tell by name that this is an object factory.

To the end:

If you do not get a factory instance here, you will return the empty object directly. If you do, you will call the getObject method to get a singleton instance. At this time, because the properties of the instance may not have been injected yet, you will put the instance into the earlySingletonObjects second level cache. To ensure that only one instance in the third level cache has a bean, So the next step is to clear it from the third-level cache.

After analyzing the createBean method, let's continue with the following logic:

		Object sharedInstance = getSingleton(beanName);
		//If a single Bean instance has been created previously and the parameters passed in by the getBean method invoked are empty, the logic inside if is executed
		//Args is required to be empty because if there are args, further assignments are required and therefore cannot be returned directly
		if (sharedInstance != null && args == null) {
			if (logger.isTraceEnabled()) {
				//If the Bean is still being created, it is a circular reference
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
							"' that is not fully initialized yet - a consequence of a circular reference");
				}
				else {
					logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
				}
			}
			//If it is a normal bean, return it directly, if it is a FactoryBean, return its getObject
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

Let's take another look at else's logic:

		//If scope is prototype or singleton mode but there are no bean s in the cache
		else {
			//If the scope is a prototype and shows that it is still being created, it is basically a circular dependency.
			//For prototype's circular dependency, spring has no solution and throws an exception directly
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			//Gets the parent container of the current container
			BeanFactory parentBeanFactory = getParentBeanFactory();
			//If a bean with the specified name cannot be found from the current container and the parent container is not empty
			if (parentBeanFactory != null && 
		!containsBeanDefinition(beanName)) {
				//Now recursively go to parentFactory to find
				//For FactoryBean, add & re-add Bean's
				String nameToLookup = originalBeanName(name);
				//If the parent container is still an instance of AbstractBeanFactory
				//Instances indicate by returning a Boolean value whether the object is an instance of a particular class or a subclass of it
				if (parentBeanFactory instanceof AbstractBeanFactory) {
					//Direct recursive call method lookup
					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
							nameToLookup, requiredType, args, typeCheckOnly);
				}
				else if (args != null) {
					//If there are parameters, the delegate parent container looks for them based on the specified name and explicit parameters
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else if (requiredType != null) {
					//Delegated to parent container to find by specified name and type
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
				else {
					//Delegate parent container to find by specified name
					return (T) parentBeanFactory.getBean(nameToLookup);
				}
			}
			//typeCheckOnly is used to determine if get Bean () is called only for type checking to get beans, not for creating beans
			if (!typeCheckOnly) {
				//Create bean s if you don't just do type checks
				markBeanAsCreated(beanName);
			}
			try {
				//Merge BeanDefinition of parent class with BeanDefinition of child class to override
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				//Validation of the merged BeanDefinition depends primarily on whether the attribute is abstract
				checkMergedBeanDefinition(mbd, beanName, args);

				// Gets the names of all dependent beans for the current Bean
				String[] dependsOn = mbd.getDependsOn();
				//If the current Bean sets the dependsOn property
				//depends-on specifies the order in which beans are initialized and destroyed
				if (dependsOn != null) {
					for (String dep : dependsOn) {
						//Verify that the dependency is registered with the current bean, noting that the key passed in here is the current bean name
						//The main thing here is to determine if there are any of the following types of dependencies
						//<bean id="beanA" class="BeanA" depends-on="beanB">
						//<bean id="beanB" class="BeanB" depends-on="beanA">
						//If so, throw the exception directly
						//As you can see, spring does not support explicit circular dependency
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						//Cache dependent calls, note that the key passed in here is the name of the dependent bean
						registerDependentBean(dep, beanName);
						try {
							//Recursively calls the get Bean method to register dependencies between beans (e.g., C needs to be initialized later than B and B needs to be initialized later than A)
							//Initialize dependent bean s
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}

				// If BeanDefinition is singleton
				if (mbd.isSingleton()) {
					//This uses an anonymous internal class, creates Bean instance objects, and registers them with dependent objects
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							//Show deleting bean instances from the singleton cache
							//Destroy it because it may already exist in singleton mode to resolve circular dependency
							destroySingleton(beanName);
							throw ex;
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}

				else if (mbd.isPrototype()) {
					// prototype creates a new object each time
					Object prototypeInstance = null;
					try {
						//The default function is to register that the currently created prototype object is being created
						beforePrototypeCreation(beanName);
						//Create prototype object instance
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						//The default function is to erase previously registered Bean information that is being created
						afterPrototypeCreation(beanName);
					}
					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}
				//Bean s to be created are neither singleton nor prototype
				//Then define the life cycle range configured in the resource based on the Bean
				//Choose the appropriate method to instantiate beans, which is common in Web applications
				//Lifecycle such as request, session, application, etc.
				else {
					String scopeName = mbd.getScope();
					final Scope scope = this.scopes.get(scopeName);
					//Bean definition is illegal if there is no scope for configuring life cycle in the resource
					if (scope == null) {
						throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
					}
					try {
						Object scopedInstance = scope.get(beanName, () -> {
							beforePrototypeCreation(beanName);
							try {
								return createBean(beanName, mbd, args);
							}
							finally {
								afterPrototypeCreation(beanName);
							}
						});
						bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
					}
					catch (IllegalStateException ex) {
						throw new BeanCreationException(beanName,
								"Scope '" + scopeName + "' is not active for the current thread; consider " +
								"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
								ex);
					}
				}
			}
			catch (BeansException ex) {
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			}
		}

Create Bean-Create Bean

The createBean method does roughly the following:

  • Bean Type Resolution
  • Processing method override
  • Post-processing before Bean instantiation
  • doCreateBean

First, we enter the AbstractAutowireCapableBeanFactory#createBean method


RootBeanDefinition is used here to receive BeanDefinition instances obtained from containers because BeanDefinition has a parent attribute, which takes out the parent's BeanDefinition attribute and merges it into the current ChildBeanDefinition, which is also acceptable for normal BeanDefinition.

Continue down:

Previously, when we used BeanDefinitionReader to load the configuration, we parsed the xml into a BeanDefinition instance, which stored the class name. By the time you resolve to BeanDefinition, you've created the Class object
Since getting a Class object is indispensable to creating a Bean instance, here is an attempt to load a Class object using the Class Loader primarily based on the class name.

Go down again:

Here comes an if judgment. First of all, the class object resolved is not empty, and the current BeanDefinition has no class object before it is resolved, but when there is a className, that is, when xml parses BeanDefinition:

	if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
			//Copy a BeanDefinition to set the loaded class object
			//This copy is used for subsequent operations because you do not want resolved class es bound to BeanDefinition in the cache
			//Because class es may need to be resolved dynamically every time
			mbdToUse = new RootBeanDefinition(mbd);
			mbdToUse.setBeanClass(resolvedClass);
		}

Since I'm using annotations here, I won't go to this step and move on:

This checks if BeanDefinition has overrides for defining methods.

Continue down:

Here we come to the resolveBeforeInstantiation method:
This method mainly performs certain types of post-processor operations.
Let's go into this method and see:

	protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
		Object bean = null;
		//If beforeInstantiationResolved is not set or false (indicating there is no action to perform before instantiation)
		if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
			//mbd.isSynthetic() defaults to false
			// If a BeanPostProcessor of InstantiationAwareBeanPostProcessors type is registered
			if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
				//Determine Bean Type
				Class<?> targetType = determineTargetType(beanName, mbd);
				if (targetType != null) {
					bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
					if (bean != null) {
						bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
					}
				}
			}
			mbd.beforeInstantiationResolved = (bean != null);
		}
		return bean;
	}

Finally, let's go back to the createBean method:

Now that you're inside doCreateBean, let's focus on the logic of doCreateBean.

doCreateBean

Above, we have studied the logic of createBean, which is to load a class object through a BeanDefinition instance. After getting the class object, we check that there are all relevant override methods, and then we will decide whether we want to customize the encapsulation of the Bean or if we don't, we will call the doCreateBean method to create the Bean instance.

Let's take a general look at what doCreateBean does:

  • A Bean instance without an attribute value is first created using a configured factory method or parameterized or parameterized construct injection
  • Post-processing of BeanDefinition is then performed to process BeanDefinition properties, which contain attributes of the @Autowired or @Value tags, and then logged for subsequent dependency injection processing
  • Then decide if early exposure is allowed
  • Fill in the Bean property, @Autowired is here
  • Call initialize Bean to initialize beans with care.
  • Register related destruction logic
  • Return to the created instance

Let's go into the source code and analyze this process:

First, it defines a BeanWrapper into which we go:

As you can see, it is an interface that Spring provides as a tool to manipulate the properties inside a Bean and use it to directly modify the properties inside a Bean.

Next move on:

	//If singleton
	if (mbd.isSingleton()) {
			//Clean up the wrapper Bean cache that was never created and retrieve the wrapper Bean instance in it. After all, it is singular and can only be saved one copy
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		//If null
		if (instanceWrapper == null) {
			//When creating beans, there are three ways to create instances of beans here
			//1. Factory Method Creation
			//2. Construction method creation
			//3. parameterless construction method injection
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		//Get the wrapped beans, and subsequent changes to the beans are equivalent to changes to Wrapper, and vice versa.
		final Object bean = instanceWrapper.getWrappedInstance();
		//Get the type of instantiated object
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}
		//BeanPostProcessor post-processing after calling BeanDefinition property merge
		// Allow post-processors to modify the merged bean definition.
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					//Attributes tagged with @Autowired, @Value are obtained here
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}

Let's go into applyMergedBeanDefinitionPostProcessors and see:

	protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof MergedBeanDefinitionPostProcessor) {
				MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
				//Focus on AutowiredAnnotationBeanPostProcessor
				//This class records member variables or method instances of tags such as @Autowired that require injection for subsequent populateBean s to use
				bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
			}
		}
	}

Let's look at the postProcessMergedBeanDefinition method:

This AutowiredAnnotationBeanPostProcessor focuses our analysis
Let's look at how it is constructed:

Inside is adding Autowired and Value to autowiredAnnotationTypes
In annotation mode, when a Bean is instantiated, AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition is called primarily to handle Autowired as well as Value and Inject tags.

Single case circular dependency resolution

So-called circular dependency is that A depends on B, and B depends on A, so let's see how Spring solves this.
Let's start by outlining the code
Let's assume that A was created first, because it's the first time, and it's wrapped in the doCreateBean method to the createBeanInstance method:

An instance of A without any attributes is generated, and then the related ObjectFactory instance is placed in the third-level cache before calling addSingletonFactory, where only the third-level cache holds the corresponding ObjectFactory instance of A.

The populateBean method is then called to assign a value to this instance.

Since A is B dependent, then within the populateBean method, the getBean method is called again to try to get instance B in the container, and since B has not yet been created, the doCreateBean method is called recursively.

Inside doCreateBean, Instance B is created through createBeanInstance, and its corresponding factory is put in the third-level cache, where the third-level cache holds the respective ObjectFactory instances of instance A and B.

We then call the populateBean method in B, where our B depends on A, so in populateBean we call the getBean method to try to get an instance of A.
At this point, because it is the doGetBean of the called AbstractBeanFactory, this method will attempt to call the getSingleton method to get an instance of A from the tertiary cache


If this is available, then the ObjectFactory instance will be taken out and the getObject method area inside will be called to get the instance of A.
Here getObject is essentially a call to the getEarlyBeanReference method inside doCreateBean to get an A instance after it has been processed by the postprocessor.

Then after acquisition:

The A instance is placed in the second level cache, the A instance in the third level cache is emptied, and the A instance is returned.
Now it's here:

Since the A instance is acquired when the B instance executes the populateBean, that is, the A instance is injected into B at this time. When B executes the populateBean, it already gets A, and B executes the remaining logic, and then it gets a complete Bean instance.

Since the doCreateBean method is called by the doGetBean method, it returns the complete B Bean instance layer by layer to the doGetBean method.
Let's go to doGetBean:

Because doGetBean is a doCreateBean that is called and then called again.
Our doCreateBean is executed when singletonFactory.getObject() is called inside the getSingleton method.

It is worth noting that the getSingleton method here is not the same as the getSingleton method mentioned above that tries to get a Bean instance from a third-level cache.

Within this method, the addSingleton method is finally called:

In the addSingleton method:

Instance B will eventually be added to the first level cache.
Removing the B instance from the secondary and tertiary caches indicates that the Bean instance creation for B has been completely completed.

A complete Bean instance of B is then returned.

However, since B was created because the A instance called populateBean to trigger it, it then returns to the populateBean method of A.

Previously, B was assigned a complete A, where A has a complete B, then A and B are both complete.
It then returns to the doGetBean method, which then calls addSingleton to place the A instance in the first level cache.


This puts the A instance in the first level cache and clears both the second and third level caches of the A instance.
This completes support for circular dependencies.

This may be a bit dizzy, so let's summarize it with the following picture:

When instance A is first created, addSingletonFactory is called to put the ObjectFactory instance of the A instance into the third-level cache. Then populateBean is called to assign attribute B to our A instance. When B is assigned, it is found that B does not exist, so getBean method is called to get the corresponding Bean instance of B.

The same is true for instance B, which first injects the ObjectFactory instance in which the B instance resides into the third-level cache, then calls the populateBean method to assign a value to the A attribute in B. Then the getBean method is called again to get the A instance, because the corresponding ObjectFactory of A has been previously put into the third-level cache. So at this point, you can get the corresponding ObjectFactory instance of A from the third-level cache, and then call the getObject method of ObjectFactory to get the instance of A.

Once you get an instance of A, you can inject it into B, which completes the creation of B. Then you put the B instance into the first-level cache, empty the other-level cache, and return its instance to A. A will then complete the creation, A will also be put into the first-level cache, and A will empty the other-level cache instances, thus completing the creation of two interdependent singletons.

Spring's support for circular dependency

Overall, Spring has two circular dependencies:

  • Constructor circular dependency (singleton, prototype)
  • Setter Injection Cyclic Dependency (singleton, prototype)

For prototype, Spring does not support related circular dependencies by default.
Because the key to resolving circular dependency depends on the third-level cache of the singleton, which solves the problem of maintaining singleton uniqueness in addition to resolving circular dependency.
Because the Bean instances taken from the cache are guaranteed to be unique, the third-level cache cannot support the prototype. After all, the prototype's Bean instances are not unique, which is why the prototype does not use the third-level cache, but just puts its name in the cache.

Because there is no support for third-level caching, prototype does not support dependent loops.

Therefore, prototype can only block an infinite loop by putting the Bean name in the cache.

Spring only supports Setter's singleton's circular dependency.

Tags: Java Zookeeper architecture eureka

Posted on Sat, 20 Nov 2021 15:08:51 -0500 by paragkalra