Hard Steel Spring source code - 50,000 words to sort out the core principles of Spring

Preface

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

Without further ado, let’s get straight to the practical stuff!

Spring core interfaces and classes

The spring framework solves a very critical problem. It allows you to use configuration files to manage the relationships between objects.

  • This is the dependency injection mechanism that it relies on, allowing dependencies between objects to be managed in Spring's IoC container.
  • By wrapping objects in Beans, you can manage objects and perform additional operations.

Bean and BeanDefinition

Spring’s first-class citizen——Bean

  • The essence of Bean is a Java object, but the life cycle of this object is managed by the container.
    Users can define a java class according to their own business needs, and tell Spring to manage the java class through configuration files/configuration classes or configuration-related annotations in a way that the Spring framework can understand. He becomes a bean in the Spring container

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

  • The way to control Java objects is reflected in the configuration

BeanDefinition - the definition of Bean

According to the configuration, generate a BeanDefinition used to describe the Bean.

Common properties:

  • scope(@Scope)
    • singleton
    • prototype
    • request
    • session
    • globalsession
  • Lazy loading lazy-init (@Lazy): determines whether the Bean instance is loaded lazily
  • Preferred primary (@Primary): The bean set to true will be the preferred implementation class
  • factory-bean和factory-method(@Configuration和@Bean)

The main things to do during container initialization
Insert image description here
First, load configuration information such as xml or annotations into the memory. These files will be treated as Resource objects in the memory, and then It is parsed into a BeanDefinition instance and finally registered in the Spring container.

When the container is initialized or the bean instance is used for the first time, the container will create the Bean instance corresponding to the BeanDifinition according to the instructions of these BeanIDifinition instance attributes. This mainly depends on the Bean creation strategy, whether to load immediately or lazily.

BeanDefinition source code exploration

Let’s take a look at BeanDefinition and its architecture members:
Insert image description here
BeanDefinition is an interface. Let’s click on the source code to see:
Insert image description here
This interface is really In the spring-beans module, this module stores interfaces and classes related to spring simple containers.

BeanDefinition inherits the two interfaces AttributeAccessor and BeanMetadataElement. Spring provides a large number of various interfaces, each of which has different capabilities. When a class implements a certain interface, it promises to have certain capabilities.

AttributeAccessor
Insert image description here
This interface defines the most basic way to modify or obtain the metadata of any object. It is mainly used in BeanDefinition to obtain the attributes of BeanDefinition and modify these attributes. Perform operations.

BeanMetadataElement
Insert image description here
This interface provides a getSource method to transmit a configurable meta object. In BeanDefinition, the BeanDefinition Class object itself is returned through the getSource method.

For BeanDefinition, it mainly describes the configuration information of a certain Bean to the Spring container.
For example, whether to delay loading isLazyInit(), get the scope getScope(), etc., there are corresponding definitions in BeanDefinition.

AbstractBeanDefinition
There are many members of the BeanDefinition family. I will only list some of the more common classes here.
AbstractBeanDefinition is the base class of the BeanDefinition implementation class

Based on AbstractBeanDefinition, Spring has derived a series of BeanDefinitions with special purposes.

  • RootBeanDefinition
  • GenericBeanDefinition
  • ChildBeanDefinition

RootBeanDefinition can be used as a BeanDefinition alone or as the parent class of other BeanDefinitions, but it cannot be used as the subclass of other BeanDefinitions.
We can take a look at its source code:
Insert image description here
You can see that an exception will be thrown once parentName is set in the setParentName method.

It needs to be added here: the inheritance relationship defined in Spring is not inherited through extends or implements, but is determined by setting the parent attribute in the BeanDefinition.

Insert image description here
As you can see from the comments of the RootBeanDefinition source code: RootBeanDefinition is usually used to receive the combined information of multiple BeanDefinitions at runtime.
There is a parent attribute in the BeanDefinition, which represents inheritance, and the RootBeanDefinition can accept two BeanDefinitions with inheritance relationships, and accept the two merged together except the parent attribute. Attributes.

Under normal circumstances, the bean tags in the configuration file will be parsed into RootBeanDefinition.

After Spring 2.5, Spring introduced a GenericBeanDefinition, replacing RootBeanDefinition and ChildBeanDefinition. But when merging attributes, RootBeanDefinition will still be used to receive them.

ChildBeanDefinition must rely on a parent BeanDefinition and cannot exist alone. However, it has been completely replaced by GenericBeanDefinition and does not need to be learned.

GenericBeanDefinition

GenericBeanDefinition is a newly added Bean file definition configuration class after Spring 2.5. It is a better alternative to RootBeanDefinition and ChildBeanDefinition.

In addition to the characteristics of other BeanDefinitions, it also has the parentName attribute to facilitate the program to set the parentBeanDefinition at runtime.

SpringIoc container

SpringIoc container is a container that manages beans. In Spring's definition, all IOC containers are required to implement the interface BeanFactory.

BeanFactory

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

Under this interface, a variable ofFACTORY_BEAN_PREFIX is defined, which is mainly used to obtain FactoryBean instances.
Insert image description here
Please note that FactoryBean and BeanFactory are two completely different things.

The difference between BeanFactory and FactoryBean

BeanFactory
BeanFactory is the root interface of the Spring container and defines the most basic functional features of the Bean factory. For example: Object getBean(String name)Get the bean instance from the container according to the bean name, etc.

BeanFactory is a container that manages beans. The beans generated by Spring are managed by the implementation class of BeanFactory.

FactoryBean
FactoryBean is also an interface. According toT getObject(), users can use a relatively complex set of logic to generate beans.

FactoryBean is also a Bean in essence, but this bean is not used to be injected into other places for use, but its function is to generate some ordinary beans. After implementing this interface, the spring container will implement this when it is initialized. Take out the bean of the interface, and then use the getObject method in the bean to generate the bean we want. Of course, the business logic for generating the bean must also be written in the getObject method.

BeanFactory architecture system

Next let's take a look at the architecture of BeanFactory:

Insert image description here
BeanFactory has a huge inheritance and implementation system, with many sub-interfaces and implementation classes. Each interface and implementation class has its use occasions. The interface is mainly used to describe the container with certain specific functions, while the implementation class implements these. functional.

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

The ApplicationContext application context advanced container is also a widely used type. Compared with BeanFactory, the advanced container adds many practical application-oriented functions, simplifying the functions originally implemented through coding in BeanFactory to configuration.

According to the single principle of programming, in fact, each top-level interface has a single responsibility and only provides a certain aspect of functionality.

ListableBeanFactory

The methods of this interface can provide Bean related information in the form of a list. The biggest feature of this interface is that it can list instance information produced by the factory in batches.

Let’s take a rough look at the methods of this interface:
Insert image description here

int getBeanDefinitionCount(); //获取BeanDefinition总数
String[] getBeanDefinitionNames(); //获取BeanDefinition名字的数组列表
String[] getBeanNamesForType(ResolvableType type);//通过指定类型获取所有Bean名字
//....
AutowireCapableBeanFactory

Let us first add two terms:

  • Component scanning: automatically discover the beans that need to be created in the application container
  • Autowiring: Automatically satisfy dependencies between beans

The logic of @Autowired automatic assembly in spring is dependency injection implemented through the interface's Object resolveDependency() method

Five assembly strategies are defined in this interface
Insert image description here
among whichAUTOWIRE_AUTODETECT has been abandoned in Spring 3.0.

int AUTOWIRE_NO = 0; //没有自动装配
int AUTOWIRE_BY_NAME = 1; //根据名称自动装配
int AUTOWIRE_BY_TYPE = 2; //根据类型自动装配
int AUTOWIRE_CONSTRUCTOR = 3; //根据构造函数自动装配

For@Autowired tags, the automatic assembly strategy isAUTOWIRE_BY_TYPEautomatic assembly based on type

DefaultListableBeanFactory

DefaultListableBeanFactory is truly an IOC container that can run independently. It inherits the abstract class AbstractAutowireCapableBeanFactory. The most important thing is that it also implements BeanDefinitionRegistry.
BeanDefinitionRegistry is the registration interface of 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 also defined in SimpleBeanDefinitionRegistry, but here it only provides registry functions and no factory functions.

Therefore, the beanDefinitonMap in DefaultListableBeanFactory is more important.

Since it is a private member variable, you need to call the method provided by DefaultListableBeanFactory to operate the BeanDefinition carrier.

ApplicationContext

Next, let's take a look at the more complex container families, the most typical of which is the ApplicationContext interface.

Spring advanced containers all implement the ApplicationContext interface
In order to distinguish them from simple containers, advanced containers are usually called Context, that is, context.

So when you hear the context, it usually means container, but it has many additional functions besides creating beans, so that users can use it out of the box based on their own needs. This is different from our previous BeanFactory factory.

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

BeanFactory is Spring's infrastructure and is oriented to the Spring framework itself, while ApplicationContext is oriented to developers who use the Spring framework.
Insert image description here
We can see that ApplicationContext is called an advanced container because it has more functions 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();

}

In this interface we see only onegetEnvironment() method, which is mainly used to obtain Environment.

To put it bluntly, it is actually to obtain some startup parameters.

It also inherits the ListableBeanFactory interface, which allows you to manage Beans through lists.

At the same time, it also implements the HierarchicalBeanFactory interface, which can support multi-level containers to manage each layer of beans.

In addition, it also inherits MessageSource, ApplicationEventPublisher, ResourcePatternResolver and many other interfaces.

They can be used to manage some Messages, implement internationalization functions, have the ability to publish events, and can be used to load resource files.

The ApplicationContext container handles events through the ApplicationEvent class and the ApplicationListener interface. If a Bean that implements the ApplicationListener interface is registered in the container, every ApplicationEvent we publish through the ApplicationContext will be notified to the registered Listener.

This is the standard observer designer pattern

ApplicationContext commonly used containers

Traditional classic container based on XML configuration:

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

Currently popular containers:

  • AnnotationConfigServletWebServerApplicationContext
  • AnnotationConfigReactiveWebServerApplicationContext
  • AnnotationConfigApplicationContext

They all have the general function of refresh()

  • Container initialization, configuration analysis
  • Registration and activation of BeanFactoryPostProcessor and BeanPostProcessor
  • International configuration
  • ……

Back in the ApplicationContext, we can see that the methods in it are read-only, that is, they all start with get, that is, only get operations are provided:
Insert image description here
So we A sub-interface is needed to provide configurable capabilities to Application. This interface is
ConfigrableApplicationContext:
Insert image description here
It inherits the Lifecycle interface and enters this interface: a>
Insert image description here

This interface provides stop, start and other methods for life cycle management.

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

When the ApplicationContext is closed, refresh can restart the container
And when it is started, calling refresh can also clear the cache and reload the configuration information< a i=2> The specific method implementation is in the AbstractApplicationContext abstract class that implements this interface.

AbstractApplicationContext

AbstractApplicationContext is implemented by combining many easy-to-change functional logic and delegating it to some of its member variables. Finally, it uses the template method pattern to let the subclass provide some function support for the parent class or set and replace the above-mentioned parent class member variables, thus The design principle of being open to expansion and closed to modification is realized, that is, the open-closed principle. Provides Spring Framework with highly flexible and scalable architectural support.

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 the access method of physical resources into Resource

Insert image description here
Basic operations on resources are defined in this interface. The Resource interface inherits the InputStreamSource interface

InputStreamSource only provides thegetInputStream() method, which returns an InputStream instance, that is, a resource stream.

Spring provides a powerful resource loading method:

  • Automatically identify resource address prefixes such as "classpath" and "file:"
  • Supports automatic parsing of Ant-style resource addresses with wildcard characters
ResourceLoader

ResourceLoader is used to implement different Resource loading strategies and return specific types of Resources on demand.

refresh method

Let’s take a look atAbstractApplicationContext#refresh the method.
Before attacking this method, let us first understand some core knowledge

PostProcessor

The Spring framework provides various PostProcessors as post-processors for containers or beans.

In fact, these PostProcessors themselves are also beans that need to be registered in the container.

  • The methods inside it will be called by the container at specific times.
  • Achieve extension of Bean without changing the container or the core logic of the Bean
  • Package the Bean, influence its behavior, and modify the content of the Bean
Types of PostProcessor

It is roughly divided into container-level post-processors and bean-level post-processors.

  • BeanDefinitionRegistryPostProcessor
  • BeanFactoryPostProcessor
  • BeanPostProcessor

The first two are container-level post-processors, and the last one is a Bean-level post-processor.

BeanDefinitionRegistryPostProcessor

Insert image description here
According to the annotation documentation, we can understand that the BeanDefinitionRegistryPostProcessor can allow more custom BeanDefinitions to be registered before the normal BeanFactoryPostProcessor detection begins.

By observing the source code, we can see that this interface inherits from BeanFactoryPostProcessor.

Only one method is provided in it:
Insert image description here
This method receives the registry parameter. You can know just by looking at the method declaration information. We need to create a BeanDefinition instance in the method body and pass in registry, register our BeanDefinition into the registry

We can take a look at the source code of BeanFactoryPostProcessor:Insert image description here
It affects the container through postProcessBeanFactory.

BeanPostProcessor

Insert image description here
For each Bean instance created by the container, the post-processor gets callback execution from the container before container initialization is called, and after any Bean initialization callbacks.

Let's look at the following example:

/**
 * Created By 小飞龙
 */
@Configuration
public class MyBeanPostProcessor implements BeanPostProcessor {
    
    

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    
    
        System.out.println(beanName+"调用了postProcessBeforeInitialization方法");
        return bean;
    }

	@Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    
    
        System.out.println(beanName+"调用了postProcessAfterInitialization方法");
        return bean;
    }
}

We implement BeanPostProcessor ourselves, and then implement its postProcessBeforeInitialization and postProcessAfterInitialization methods.
Then start the project:
Insert image description here
After execution, we can see that these two methods will be executed for each Bean, and they will be executed first postProcessBeforeInitializationExecute againpostProcessAfterInitialization.

Seeing this, can anyone have a flash of inspiration? Can we use the ability of BeanPostProcessor to package the Bean, that is, after the Bean is created, package the Bean in postProcessAfterInitialization The upper layer of general logic, such as unified logging of some time-consuming statistics, enhanced behavior and return to the Bean, again involves the scope of AOP.

Let’s first understand so much about PostProcessor, which mainly involves the post-processor of the container and the post-processor of the Bean. The framework itself also provides many implementation classes for PostProcessor. Each PostProcessors implementation class has different scene requirements. Spring Applying these different implementation classes completes the tasks of the framework itself, mainly in the container startup and Bean acquisition stages. In addition, we can also implement Processor ourselves to expand its capabilities.

Aware

In order to facilitate the smooth acquisition of subsequent knowledge, we will learn an important interface Aware

We learned earlier that the container is basically non-invasive to the logic of the Bean itself. Therefore, the Bean generally does not need to know the status of the container and use the container directly. However, in some cases, it is necessary to directly access the container in the Bean. To operate, you need to set the awareness of the container in the Bean. This is the role of Aware.
Insert image description here
In Aware we can see that there is no method, it can only be used as a label, so what Aware can directly play a role in Spring is its own inherited Aware interface subinterface.

Common Aware sub-interfaces are as follows:

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

Insert image description here
In this interface, we can see that it defines a method setApplicationContext.
This method is to let the Bean that implements the interface pass the container's own instance as a parameter when the container creates the Bean instance for use by the Bean.

BeanNameAware

Let’s look at the next sub-interface BeanNameAware:
Insert image description here
In this interface we can also see that only one method is definedsetBeanName
Its function is to pass in the name of the Bean for use by the implementation class of the interface

BeanFactoryAware

Mainly used to obtain the current BeanFactory so that the container's services can be called

MessageSourceAware

Mainly used to obtain text information related to MessageSource

ApplicationEventPublisherAware

Mainly used to obtain publisher instances to publish events

ResourceLoadAware

Mainly used to obtain resource loaders, through which we can obtain external resource files

Let's demonstrate it through code:

/**
 * Created By 小飞龙
 */
@RestController
public class TestController implements ApplicationContextAware, BeanNameAware {
    
    
    private String myName;
    @Autowired
    private ApplicationContext myContainer;
    
    @GetMapping("/getMyName")
    public String  handleRequest(){
    
    
        System.out.println("我是:"+myName);

        String[] names = myContainer.getBeanDefinitionNames();
        for (String name : names) {
    
    
            System.out.println("获取注册到容器的BeanDefinition名称:"+name);
        }
        return "OK";
    }

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

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

    }
}

After the writing is completed, start the project, and then open Postman to test it:
Insert image description here
After testing, we found that we can indeed obtain the resources we want. It is worth noting here that we In order to obtain container resources, in addition to implementing the Aware interface, you must also register as a container-managed bean.

Spring event notification mechanism

event listener pattern

The listener will listen for events of interest and respond once the event occurs. The event listener involves three components:

  • Event Source
  • Event Listener
  • Event Object

Let's demonstrate it through code:

1. Create an event

@Data
public class Event {
    
    
    private String type;
}

2. Create 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("单机事件被触发...");
        }
    }
}
public class DoubleClickEventListener implements EventListener{
    
    
    @Override
    public void processEvent(Event event) {
    
    
        if ("double".equals(event.getType())){
    
    
            System.out.println("双击事件被触发...");
        }
    }
}

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 the main function and test it

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");

        //注册时间监听器
        eventSource.register(singleClickEventListener);
        eventSource.register(doubleClickEventListener);

        //发布事件
        eventSource.publishEvent(event);
    }

Insert image description here
After testing, we found that the event source broadcast the double-click event to all registered listeners, but only the listeners interested in the event responded to the event.
The above is the rough implementation of the event listener pattern. The event listener is actually an implementation of the classic design pattern observer pattern.

Spring event driven model

Insert image description here

The three major components of the event-driven model:

  • Event: ApplicationEvent abstract class

    • ContextStoppedEvent: event triggered after the container is stopped
    • ContextRefreshedEvent: event triggered after container initialization or refresh is completed
    • ContextCloseEvent: event triggered after the container is closed
    • ContextStartedEvent: event triggered after the container is started
  • Event listener: ApplicationListener

  • event publisher

    • ApplicationEventPublisher
    • ApplicationEventMulticaster
event

Let’s take a look at the ApplicationEvent source code first:
Insert image description here
We found that in the constructor of this abstract class, a parameter of type Object will be accepted, and source refers to the event source. .

Before Spring 4.2, events must inherit ApplicationEvent, and after 4.2, the framework provides a PayloadApplicationEvent:
Insert image description here
It is a subclass of ApplicationEvent because it is a generic class, Therefore, any type can be packaged, and the event will no longer be forced to inherit ApplicationEvent. After we send an event of any type inside the container, the framework will automatically package it into the PayloadApplicationEvent event object.

event listener

Insert image description here
The listener in Spring inherits EventListener. Let’s take a look at the source code of ApplicationListener:
Insert image description here
As you can see, there is only onApplicationEvent in ApplicationListener. Method, the parameter it accepts is ApplicationEvent, this method is used to handle events.

Spring also defines two sub-interfaces of ApplicationListener, providing the ability to filter events.
Both SmartApplicationListener and GenericApplicationListener inherit the Ordered interface and have the ability to sort. They give listeners a priority in order from small to large to ensure the order of execution.

Insert image description here
We can see from the source code that the events filtered by GenericApplicationListener use ResolvableType compared to SmartApplicationListener, and ResolvableType is a tool added after Spring 4.0 to obtain generic information. It can obtain various information about the incoming generics. kind of information, similar to the reflection mechanism.

event publisher

The main interfaces designed by the event publisher are

  • ApplicationEventPublisher
  • ApplicationEventMulticaster

Using these two interfaces, our service has the ability to publish events.

ApplicationEventPublisher

When you see this interface, it seems a bit familiar.
Insert image description here
We found that ApplicationContext implements ApplicationEventPublisher, which also shows that ApplicationContext has the ability to publish events.

Since we have an ApplicationEventPublisher, why do we need an ApplicationEventMulticaster?
Let’s first take a look at the source code of ApplicationEventPublisher:
Insert image description here
You can see that there are only two methods in it, both related to publishing events. In other words, we This interface can only be used to publish events.

ApplicationEventMulticaster

According to what we learned earlier, the event source should have a place to register Linstener. With this problem, let’s take a look at the source code of ApplicationEventMulticaster:
Insert image description here
From the source code we As you can see, these two interfaces do not have any inheritance relationship, but ApplicationEventMulticaster has methods to add and delete ApplicationListener, and also provides methods to publish events.

Let’s take a look at the main members of ApplicationEventMulticaster:
Insert image description here
As you can see, Spring has set up an abstract class of AbstractApplicationEventMulticaster as the default implementation of ApplicationEventMulticaster.
Let’s go into the source code and take a look:
Insert image description here
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 and take a look:Insert image description here
You can see that there is indeed a Set type applicationListeners, which is used to receive ApplicationListener, because our ApplicationListener is also some Bean, so the following Another collection is dedicated to saving the Bean names of these Listeners.

Because AbstractApplicationEventMulticaster is only an abstract class, if there is no local implementation of AbstractApplicationEventMulticaster, the default implementation of SimpleApplicationEventMulticaster will be used.
Insert image description here
Entering the source code, we found that it has a member variable of taskExecutor, which is an executor, which means that it supports multi-threaded processing of listeners. method.
Let’s take a look at this method:
Insert image description here

	@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 the executor is not empty, it will use multi-threading to process events asynchronously. If the executor is not set, it will execute the listeners one by one in a synchronous manner. .

Why not just use ApplicationEventMulticaster instead of ApplicationEventPublisher

From a designer's point of view, it is an easy thing to understand. For example, beans and containers themselves only want to publish an event and do not want to maintain event listeners, so Spring takes the event source a step further. Split, abstract the event publisher interface, and then use ApplicationEventMulticaster as a proxy to let the implementation class of ApplicationEventPublisher implement the logic insidepublishEvent.

AndpublishEvent is mainly used to call the multicastEvent method of the ApplicationEventMulticaster implementation class to publish events.

Attack the refresh method and tear apart the container refresh logic

Now that the outer lines of defense of the container have been conquered, we began to attack the initialization logic of the container. It mainly attacks the common part in various advanced containers, namely the refresh method of AbstractApplicationContext.

Its main function is to refresh the Spring container. Refreshing means clearing the BeanFactory to its initial state, and then filling it with various bean instances according to the figure below.

Refresh is also a common test point for Spring framework interviews, so we must work hard and study it carefully.

Insert image description here
After understanding, we directly put a breakpoint on the first line of refresh, and then start the container:
Insert image description here
The synchronized step is mainly to add a synchronization lock to the container to avoid the container processing. During the refresh phase, other threads are still initializing or destroying the container

You will then enterprepareRefresh() this method, which is mainly used to prepare for refreshing the container.
In this method, the following things are mainly done

	protected void prepareRefresh() {
    
    
        // Switch to active.
        //设置当前时间,也就是容器启动时间,方便后续日志记录,还有容器执行的一些统计工作
        this.startupDate = System.currentTimeMillis();
        //设置非关闭状态
        this.closed.set(false);
        //设置为激活状态
        this.active.set(true);
        //配置日志等级
        if (logger.isDebugEnabled()) {
    
    
            if (logger.isTraceEnabled()) {
    
    
                logger.trace("Refreshing " + this);
            } else {
    
    
                logger.debug("Refreshing " + getDisplayName());
            }
        }
        //初始化环境(Evironment)的propertySource属性
        //样例: <context:property-placeholder location="classpath*:/config/load.properties"/>
        initPropertySources();

        //校验Environment的requiredProperties是否都存在
        getEnvironment().validateRequiredProperties();

        //看看容器启动的时候是否有加载一些监听器,默认情况下earlyApplicationListeners为null
        if (this.earlyApplicationListeners == null) {
    
    
            this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
        } else {
    
    
            this.applicationListeners.clear();
            this.applicationListeners.addAll(this.earlyApplicationListeners);
        }
        //创建事件集合
        this.earlyApplicationEvents = new LinkedHashSet<>();
    }

You will then enter theobtainFreshBeanFactory method:
Insert image description here
This step mainly involves the registration of BeanDefinition
This step is for The xml configuration is very important, but for annotations, it only calls the refreshBeanFactory of the subclass
. We enter this method:
Insert image description here
and then enter Go to refreshBeanFactory:
Insert image description here
For annotations, it actually calls the refreshBeanFactory method in GenericApplicationContext
and in the xml configuration Calling refreshBeanFactory is mainly used to generate the DefaultListableBeanFactory internal container instance, and then register the BeanDefinition to the DefaultListableBeanFactory internal container instance. As for the annotations we use here, it is not that complicated. DefaultListableBeanFactory is created when the container's constructor is called.

Therefore, this is mainly used to update the refresh status of the AnnotationApplicationContext instance, and at the same time set the serializationId for its internal DefaultListableBeanFactory to facilitate external serialization through the network to obtain the exclusive DefaultListableBeanFactory instance here.

Let’s take a look at the prepareBeanFactory method again
Insert image description here
At this point we have received the DefaultListableBeanFactory instance.
Enter the prepareBeanFactory method:

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    
    
		// Tell the internal bean factory to use the context's class loader etc.
		//告诉内部Bean工厂使用容器的类加载器
		beanFactory.setBeanClassLoader(getClassLoader());
		//设置BeanFactory的表达式语言处理器,Spring3开始增加了对语言表达式的支持,默认可以使用#{bean.xxx}获取bean里面的实例值
		beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
		//为beanFactory增加一个默认的PropertyEditor
		beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

		//添加后置处理器,作用是:当应用程序定义的Bean实现ApplicationContextAware接口时注入ApplicationContext对象
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

		//如果某个Bean依赖于一下某个接口的实现类,在自动装配的时候会忽略他们
		//Spring会通知其他方式处理这些依赖
		beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
		beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
		beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
		beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

		//修正依赖,这里是注册一些自动装配的特殊规则,比如是BeanFactory class接口的实现类则在运行时指定为当前BeanFactory
		beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
		beanFactory.registerResolvableDependency(ResourceLoader.class, this);
		beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
		beanFactory.registerResolvableDependency(ApplicationContext.class, this);

		//注册早期后置处理器,用于检测内部bean作为应用程序的监听器
		//ApplicationListenerDetector的作用就是判断某个Bean是否是ApplicationListener
		//如果是,加入到事件监听者队列
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

		// 如果找到一个LoadTimeWeaver,那么就将准备后置处理器“织入”bean工厂
		if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
    
    
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			// 为类型匹配设置临时类加载器
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}

		// 注册默认environment环境bean
		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());
		}
	}

After reading this, we go back to the refresh method and enter the postProcessBeanFactory method.
Insert image description here
This method is used to allow the container to register the necessary postProcess and is a hook method.
The hook method can be implemented or not implemented by subclasses.
Follow up:
Insert image description here
We will find that for this container There is no need to register a subclass of PostProcessor

Continue to execute and you will come toinvokeBeanFactoryPostProcessorsthis method
Insert image description here
The main function of this method is to register the container-level PostProcessor

If we continue to execute, we will come toregisterBeanPostProcessorsThis method
Insert image description here
After completing the container-level post-processor, there is the Bean-level post-processor The processor is reset.

The step of registerBeanPostProcessors is to register the previously defined bean-level post-processors into the container, so that when the getBean method is called later to create a Bean instance, these post-processors can be triggered at specific links to execute some specific logic. .

With this kind of bean-level post-processor, it is convenient for us to conduct refined and customized management of beans.

Go down to theinitMessageSourcemethod
Insert image description here
Here we mainly carry out some international configurations, the main purpose is to display them in different regions Different language content.

Continue execution and you will enterinitApplicationEventMulticaster()
Use this method to initialize the event publisher, which is used to receive different events sent by classes that implement the ApplicationEventPublisher interface and dispatch to different events The listener handles it.
Insert image description here
When entering this method, we first see that it first determines whether the container has previously registered a custom event publisher, and if so, it can be used directly.
Otherwise, the default SimpleApplicationEventMulticaster will be used as the event publisher.
Insert image description here
We can see that SimpleApplicationEventMulticaster was indeed created to support event publishing.
After executing this, we have created SimpleApplicationEventMulticaster.

The onRefresh() method is executed next
Insert image description here
This method is also a hook method, mainly reserved for its subclasses and used to initialize other special beans. This method will Occurs before the finishBeanFactoryInitialization method in the refresh method, that is, before the instantiation of the singleton Bean.
The onRefresh method is generally used on some web containers

Continue to execute

Insert image description here
This method is to register a listener with our previous ApplicationEventMulticaster to listen for different events. After all, events and event publishers alone cannot constitute a complete event listening mechanism. Having a listener is complete.

Continue executing and you will come to the finishBeanFactoryInitialization method
Insert image description here
Enter this method:
Insert image description here
We will find that this method will first determine whether there is any The automatic type converter ConversionService, if available, obtains the Bean instance that provides type conversion from the container through getBean. The so-called type converter converts the attribute 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 require these converters to handle them.

Further down:
Insert image description here

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

Continue to execute:

// 停止使用临时类加载器进行类型匹配
beanFactory.setTempClassLoader(null);

Then stop using the temporary class loader, because the aop operation has been completed, and there is no need to use the temporary class loader to load the proxy class generated by jvm
Then proceed:

// 允许缓存所有bean定义元数据,不希望有进一步的更改
beanFactory.freezeConfiguration();

This step is mainly used to freeze container-related configurations. This step makes the previously refreshed content stored in the memory reliable and stable.

See next step

// 实例化所有剩余的(non-lazy-init非延时加载的)单例
   beanFactory.preInstantiateSingletons();

This step is to first instantiate all remaining bean instances that are not lazy-loaded by default and have a singleton scope.

For the Spring advanced container, the default beans are singletons and are not lazy loaded, so the corresponding bean instances will be created and managed here
Insert image description here
Follow up , we will find that it enters the class DefaultListableBeanFactory
Insert image description here
Skip the log, let’s look at the following logic:

First, it traverses the registered BeanDefinition names, and then goes to the corresponding BeanDefinition instance based on the name.

RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);

Here, the merged BeanDefinition is accepted through RootBeanDefinition. The call level of getMergedLocalBeanDefinition is relatively deep and difficult to analyze, so we only need to remember its function.

The function of MergedLocalBeanDefinition is to be compatible with various BeanDefinitions.

Different Beans are instantiated when loading the SpringBean definition. GenericBeanDefinition can be directly converted into RootBeanDefinition, so there is no problem with ordinary BeanDefinition.

For another situation, it also supports ChildBeanDefinition with inheritance relationship. Its parent will specify another BeanDefinition, which will merge the properties of ChildBeanDefinition and parent BeanDefinition together, or it can be converted into RootBeanDefinition and returned . Therefore, in order to be compatible with the original ChildBeanDefinition, it is reasonable 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 judge here, first of all, this BeanDefinition instance is not abstract, and is a singleton and non-lazy loading.

If all are satisfied, instantiation begins.

Then first determine whether the bean is a FactoryBean. If so, it will go to the container to obtain a FactoryBean instance.

If you obtain it, then determine whether the beans in FactoryBean are lazy loaded. If not, isEagerInit, and the relevant creation method has permission to accessgetAccessControlContext(), then Create the beans in FactoryBean through getBean.

Insert image description here
A SmartFactoryBean is involved here. Let's take a look at this interface.

Insert image description here
It can set whether the instance is lazy loaded or non-lazy loaded.

Spring dependency injection

In order to implement the life cycle control of the Bean, Spring will also consider that it or the user may customize the behavior of the Bean at each stage during the process of instantiating the Bean. Therefore, the entire output process Extremely complex.
There are thousands of lines of core code alone. If you go into the details one by one, you will definitely get dizzy.
But as long as we grasp the skeleton and understand the core parts, the effect will be much better. Therefore, if we first understand the context, and then study the details, we will find that it will become clearer and clearer.

In the refresh method in AbstractApplicationContext:

//实例化所有剩余的(non-lazy-init非延迟加载的)单例
beanFactory.preInstantiateSingletons();

In this method, those non-lazy-loaded bean instances will be initialized. The beans managed by our ApplicationContext container by default are singletons and are non-lazy-loaded.
Therefore, if there is no special setting, the bean will call the getBean method for instantiation at this step.
Therefore, the getBean method here is the focus of our next study, and dependency injection is also completed here.

There are many methods of dependency injection. We focus on injection based on @Autowired method.

The editor here still wants to remind everyone that the nesting level of dependency injection is very deep, and it jumps among multiple classes. If you want to understand the details inside, let alone everyone, the editor is already dizzy. The dish is ready.

So we must change our thinking. Since it is too difficult, we can only defeat it one by one by grasping the key points, not being reluctant to fight, and understanding the whole picture.
Therefore, we also need to open the national map to fight:
Insert image description here
This route is based on the injection and analysis of @Autowired.

We can conquer each module one by one from top to bottom. The so-called conquering does not mean that we have to understand all the details and every line of code. We only need to understand its general function.

Our goal is very clear, mainly to understand the implementation ideas of dependency injection, so as to minimize the learning cost and maximize the learning effect.

In the mind map, after just attacking the source code, we can see that it is a deepening process from top to bottom.
Next, let’s take a rough look at what each module does.

The first is AbstractBeanFactory, which is an abstract class that provides a method for obtaining bean instances. This method involves different processing according to different scopes.

This article mainly studies the situation of singleton, so we mainly look at the DefaultSingletonRegistry class. We can know from the name that it is the default implementation class for singleton bean registration. This class provides the method getSingleton to obtain a singleton instance.

````getSingleton```` This method will try to obtain the Bean instance from the three-level cache. The reason why the three-level cache is separated is mainly to solve the problem of circular dependency.

If the Bean instance is not found in the cache, the container will be created, so it will go to the AbstractAutowireCapableBeanFactory, which will call the createBean method to do some preparatory work before creation. Then call doCreateBean to create a Bean instance.

It is not enough to just create a Bean instance in doCreateBean. You also need to check whether the attributes in the bean instance have been @Autowired or @Value etc. The dependency injection tag is marked, and if there is one, the relevant mark is made. Our applyMergedBeanDefinitionPostProcessors is mainly used for post-processing the merged BeanDefinition, which also involves processing related logic.

After is marked, it will consider assigning values ​​to the member variables of the Bean, so dependency injection is implemented in populateBean.

Our assault force only assaulted to this level.

Later, he will do post-processing of attributes through the postProcessProperties method of AutowiredAnnotationBeanPostProcessor to implement the injection logic of @Autowired. If you go deeper layer by layer, you will come to DefaultListableBeanFactory. To parse dependencies, this is mainly because BeanDefinitions are stored here, and by viewing BeanDefinitions we can find the dependencies between Beans.

After finding the dependency, the service provided in the DependencyDescriptor class will be called for injection.

The above is the entire dependency injection process. This is just a rough outline, in fact it is far from that simple.

doGetBean

Insert image description here
Here we mainly study the getBean method, and what really works in the getBean method is the doGetBean method. Let’s take a look at what this method mainly does:

  1. First, he will try to obtain a singleton Bean instance from the container's cache. This singleton Bean may be a Bean or a FactoryBean instance itself. If it is a Bean, it will be returned directly. If it is a FactoryBean, it will be retrieved through the getObject method. Return bean instance. If it cannot be obtained at this step, you need to let the container create the bean.
  2. Next is the judgment logic of circular dependencies. It is precisely because of circular dependencies that the third-level cache is used.
  3. If there is no BeanDefinition instance of the bean registered in the current container, it will recursively go to the parent class container to find it.
  4. If there is a BeanDefinition of the bean in the current container, obtain its instance from the container.
  5. Recursively instantiate explicitly dependent beans. The so-called explicit means setting a deoends-on for the bean.
  6. Create Bean instances using different strategies according to different scopes
  7. Type checking beans

With these macro-understandings, it is not difficult to conquer this part of the code. We will directly open the city gate to fight!

Directly open the code of the doGetBean method of AbstractBeanFactory
Look at the first line first:
Insert image description here
The first line is the name of the Bean passed in getBean Convert it to the real beanName in the container, because the name passed in may be the bean itself or the name of FactoryBean with the ampersand symbol, or it may be an alias passed in, so we need to uniformly convert it into beanName.

After getting the beanName, you will enter the next line of code.

//尝试从一级缓存里面获取完备的Bean
Object sharedInstance = getSingleton(beanName);

Enter this method:
Insert image description here
We can see that it calls an overloaded method. The second parameter allowEarlyReference is true, allowing non-delayed loading, that is, immediate loading. . Let's get into the method.

	@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    
    
		//尝试从一级缓存里面获取完备的Bean
		Object singletonObject = this.singletonObjects.get(beanName);
		//如果完备的Bean还没有创建出来,创建中的Bean的名字会被保存在singletonsCurrentlyInCreation中
		//因此看看是否正在创建
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
    
    
			//尝试给一级对象加锁,因为接下来就要对缓存对象操作
			synchronized (this.singletonObjects) {
    
    
				//尝试从二级缓存earlySingletonObject这个存储还没有进行属性添加操作的Bean实例缓存中获取
				singletonObject = this.earlySingletonObjects.get(beanName);
				//如果二级缓存还没有获取到并且第二个参数为true,为true则表示bean允许被循环引用
				if (singletonObject == null && allowEarlyReference) {
    
    
					//从三级缓存singletonFactories这个ObjectFactory实例的缓存里尝试获取创建此Bean的单例工厂实例
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					//如果获取到工厂实例
					if (singletonFactory != null) {
    
    
						//调用工厂的getObejct方法返回对象实例
						singletonObject = singletonFactory.getObject();
						//将实例放入二级缓存
						this.earlySingletonObjects.put(beanName, singletonObject);
						//从三级缓存里移除
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

He will first try to obtain the singleton instance corresponding to beanName from a ConcurrentHashMap of singletonObjects, where singletonObjects is the first-level cache of the singleton cache. It is mainly used to save the singleton bean instance in its final form.

Then because this is the first time we call getBean of the container to create a non-lazy-loaded singleton in advance, it cannot be found in the cache. Then you will enter the following if statement. The if statement is mainly to ensure that the bean instance cannot be obtained from the first-level cache and that the instance is being created.
Let’s take a look at the isSinglesonCurrentlyInCreation method in if:
Insert image description here

Insert image description hereThis step is mainly used to find whether there is a beanName in the list of singleton beans being created to solve the problem of circular dependencies.

Then in the if logic below, first add a synchronization lock to the first-level cache object to operate the subsequent cache to prevent threads from operating the cache at the same time.
Insert image description here

After locking, we come to earlySingletonObjects. Since singletonObjects, the first-level cache that supports multi-threaded operations, has been locked, operations on other caches are thread-safe and synchronous. In order to improve performance, the other two caches are used HashMap

earlySingletonObjects are beans that have not yet called the populateBean method to assign values ​​to properties.

If it is obtained in this step, it will return directly. If it is not obtained and allowEarlyReference is true, it will enter the if and try to obtain it from another cache singletonFactories. This is the third layer cache and is stored here. is the ObjectFactory instance corresponding to the Bean. We can tell from the name that this is an object factory.

To the end:
Insert image description here
If the factory instance is not obtained here, an empty object will be returned directly. If it is obtained, the getObject method will be called to obtain the singleton instance. At this time Since the properties of the instance may not have been injected yet, the instance is put into the earlySingletonObjects second-level cache at this time. In order to ensure that only one of the third-level caches has an instance of a certain bean, the next step will be to remove it from the third-level cache. Clear it out.

After analyzingcreateBean the method, we continue to analyze the following logic:

		Object sharedInstance = getSingleton(beanName);
		//如果先前已经创建过单例Bean实例,并且调用的getBean方法传入的参数为空,则执行if里面的逻辑
		//args之所以要求为空是因为如果有args,则需要做进一步赋值,因此无法直接返回
		if (sharedInstance != null && args == null) {
    
    
			if (logger.isTraceEnabled()) {
    
    
				//如果Bean还在创建中,则说明是循环引用
				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 + "'");
				}
			}
			//如果是普通的bean,直接返回,如果是FactoryBean,则返回它的getObject
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

Let’s take a look at the else logic below:

		//若scope为prototype或者单例模式但是缓存中还不存在bean
		else {
    
    
			//如果scope为prototype并且显示还在创建,则基本是循环依赖的情况。
			//针对prototype的循环依赖,spring无解,直接抛出异常
			if (isPrototypeCurrentlyInCreation(beanName)) {
    
    
				throw new BeanCurrentlyInCreationException(beanName);
			}

			//获取当前容器的父容器
			BeanFactory parentBeanFactory = getParentBeanFactory();
			//如果从当前容器找不到指定名称的bean,并且父容器不为空
			if (parentBeanFactory != null && 
		!containsBeanDefinition(beanName)) {
    
    
				//此时递归去parentFactory查找
				//主要针对FactoryBean,将Bean的&重新加上
				String nameToLookup = originalBeanName(name);
				//如果parent容器依旧是AbstractBeanFactory的实例
				//instance通过返回一个布尔值来指出,这个对象是否是特定类或者是它的子类的一个实例
				if (parentBeanFactory instanceof AbstractBeanFactory) {
    
    
					//直接递归调用方法来查找
					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
							nameToLookup, requiredType, args, typeCheckOnly);
				}
				else if (args != null) {
    
    
					//如果有参数,则委派父级容器根据指定名称和显式的参数查找
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else if (requiredType != null) {
    
    
					//委派给父级容器根据指定名称和类型查找
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
				else {
    
    
					//委派父级容器根据指定名称查找
					return (T) parentBeanFactory.getBean(nameToLookup);
				}
			}
			//typeCheckOnly是用来判断调用getBean()是否仅仅是为了类型检查获取bean,而不是为了创建Bean
			if (!typeCheckOnly) {
    
    
				//如果不是仅仅做类型检查则是创建bean
				markBeanAsCreated(beanName);
			}
			try {
    
    
				//将父类的BeanDefinition与子类的BeanDefinition进行合并覆盖
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				//对合并的BeanDefinition做验证,主要看属性是否为abstract的
				checkMergedBeanDefinition(mbd, beanName, args);

				// 获取当前Bean所有依赖Bean的名称
				String[] dependsOn = mbd.getDependsOn();
				//如果当前Bean设置了dependsOn的属性
				//depends-on用来指定Bean初始化及销毁时的顺序
				if (dependsOn != null) {
    
    
					for (String dep : dependsOn) {
    
    
						//校验该依赖是否已经注册给当前bean,注意这里传入的key是当前的bean名称
						//这里主要是判断是否有以下类型的依赖
						//<bean id="beanA" class="BeanA" depends-on="beanB">
						//<bean id="beanB" class="BeanB" depends-on="beanA">
						//如果有,则直接抛出异常
						//由此可以看出,spring是不支持显式的循环依赖
						if (isDependent(beanName, dep)) {
    
    
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						//缓存依赖调用,注意这里传入的key是被依赖的bean名称
						registerDependentBean(dep, beanName);
						try {
    
    
							//递归调用getBean方法,注册Bean之间的依赖(如C需要晚于B初始化,而B需要晚于A初始化)
							//初始化依赖的bean
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
    
    
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}

				// 如果BeanDefinition是单例
				if (mbd.isSingleton()) {
    
    
					//这里使用一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象
					sharedInstance = getSingleton(beanName, () -> {
    
    
						try {
    
    
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
    
    
							//显示从单例缓存中删除bean实例
							//因为单例模式下为了解决循环依赖,可能它已经存在了,所以将其销毁
							destroySingleton(beanName);
							throw ex;
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}

				else if (mbd.isPrototype()) {
    
    
					// prototype每次都会创建一个新对象
					Object prototypeInstance = null;
					try {
    
    
						//默认的功能是注册当前创建的prototype对象正在创建中
						beforePrototypeCreation(beanName);
						//创建原型对象实例
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
    
    
						//默认的功能是将先前注册的正在创建中的Bean信息给抹除掉
						afterPrototypeCreation(beanName);
					}
					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}
				//要创建的Bean既不是单例模式,也不是原型模式
				//则根据Bean定义资源中配置的生命周期范围
				//选择实例化Bean的合适方法,这种在Web应用程序中比较常用
				//如:request、session、application等生命周期
				else {
    
    
					String scopeName = mbd.getScope();
					final Scope scope = this.scopes.get(scopeName);
					//Bean定义资源中没有配置生命周期的范围,则Bean定义不合法
					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;
			}
		}

Attack the creation of Bean——createBean

The createBean method roughly does the following:

  • Bean type resolution
  • Handling method override
  • Post-processing before bean instantiation
  • doCreateBean

First, we enter theAbstractAutowireCapableBeanFactory#createBean method
Insert image description here
Insert image description here
Here we use RootBeanDefiniton to receive the BeanDefinition instance obtained from the container. The reason is that BeanDefinition has a parent Attribute, it will take out the parent's BeanDefinition attribute and merge it into the current ChildBeanDefinition. For ordinary BeanDefinition, RootBeanDefinition can also be received.

Continue going down:
Insert image description here
Previously, when we used BeanDefinitionReader to load the configuration, we parsed the xml into a BeanDefinition instance, and the BeanDefinition instance stored the name of the class. In the step of parsing into BeanDefinition, the Class object has already been created
Since you want to create a Bean instance, it is indispensable to obtain the Class object, so here mainly based on the name of the class, try Use the class loader to load the class object.

Go further:
Insert image description here
Here we enter an if judgment. First, it is judged that the parsed class object is not empty, and the current BeanDefinition does not have a class object before parsing. But when there is className, that is, when xml parses BeanDefinition:

	if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
    
    
			//拷贝一份BeanDefinition,用来设置加载出来的class对象
			//之所以后续用该副本进行操作,是因为不希望解析的class绑定到缓存里的BeanDefinition
			//因为class有可能是每次都需要动态解析出来的
			mbdToUse = new RootBeanDefinition(mbd);
			mbdToUse.setBeanClass(resolvedClass);
		}

Since I am using annotations here, I will not go to this step, and then go down:
Insert image description here
Here, check whether the BeanDefinition has coverage of the definition method.

Continue going down:
Insert image description here
Here we come to resolveBeforeInstantiation this method:
This method mainly executes certain types of postprocessor operations.
Let’s go into this method and take a look:

	protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    
    
		Object bean = null;
		//如果beforeInstantiationResolved还没有设置或者为false(说明还没有需要在实例化前执行的操作)
		if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
    
    
			//mbd.isSynthetic()默认是false
			// 如果注册了InstantiationAwareBeanPostProcessors类型的BeanPostProcessor
			if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
    
    
				//确定Bean的类型
				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 we return to the createBean method:

Insert image description here

At this point, we come to doCreateBean. Next, we will focus on the logic of doCreateBean.

doCreateBean

Above, we have studied the logic ofcreateBean, which mainly involves loading the class object through the BeanDefinition instance. After obtaining the class object, we check that there are related override methods, and then It will determine whether to perform custom encapsulation processing on the Bean. If not, the doCreateBean method will be called to create the Bean instance.

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

  • First, a Bean instance without attribute values ​​will be created through the configured factory method or parameter-containing construction injection or no-parameter construction injection.
  • After , the post-processing of the BeanDefinition will be executed to process the attributes of the BeanDefinition, which include the attributes marked with @Autowired or @Value, and then record them for convenience. Subsequent dependency injection processing
  • Then determine whether early exposure is allowed
  • Fill the Bean properties,@Autowired is done here
  • CallinitializeBean to fully initialize the Bean.
  • Register related destruction logic
  • Return the created instance

Let’s go into the source code and analyze this process:
Insert image description here
First, it defines a BeanWrapper. Let’s go into the source code of this BeanWrapper:
Insert image description here
As you can see, it is an interface, which is a tool provided by Spring to operate the properties in the Bean. You can use it to directly modify the properties in the Bean.

Next, continue down:

	//如果是单例
	if (mbd.isSingleton()) {
    
    
			//从未完成创建的包装Bean缓存中清理并获取相关中的包装Bean实例,毕竟是单例的,只能存一份
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		//如果是null
		if (instanceWrapper == null) {
    
    
			//创建bean的时候,这里创建bean的实例有三种方法
			//1.工厂方法创建
			//2.构造方法创建
			//3.无参构造方法注入
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		//获取被包装的Bean,后续对Bean的改动相当于对Wrapper的改动,反之亦然。
		final Object bean = instanceWrapper.getWrappedInstance();
		//获取实例化对象的类型
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
    
    
			mbd.resolvedTargetType = beanType;
		}
		//调用BeanDefinition属性合并完成后的BeanPostProcessor后置处理
		// Allow post-processors to modify the merged bean definition.
		synchronized (mbd.postProcessingLock) {
    
    
			if (!mbd.postProcessed) {
    
    
				try {
    
    
					//被@Autowired、@Value标记的属性在这里获取
					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 enter againapplyMergedBeanDefinitionPostProcessors and take a look at this method:

	protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
    
    
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
    
    
			if (bp instanceof MergedBeanDefinitionPostProcessor) {
    
    
				MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
				//重点关注AutowiredAnnotationBeanPostProcessor
				//该类会把@Autowired等标记的需要依赖注入的成员变量或者方法实例给记录下来,方便后续populateBean使用
				bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
			}
		}
	}

Let’s take a lookpostProcessMergedBeanDefinitionThis method:

Insert image description here

This AutowiredAnnotationBeanPostProcessor is the focus of our analysis
Let’s take a look at its construction method:
Insert image description here
Inside it is Autowired and Value are added to autowiredAnnotationTypes
In annotation mode, when a Bean is instantiated, AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition will be called It is mainly used to process the tags of Autowired, Value and Inject.

Singleton circular dependency resolution

The so-called circular dependency means that A depends on B, and then B depends on A. Let’s take a look at how Spring solves this situation.
Let’s talk about it based on the code first.
We assume that A is created first. Since it is the first time it is created, it enters method: At this time, an instance of A without any attributes will be generated, and then it will be Before calling , put the relevant ObjectFactory instance in the third-level cache. At this time, only the third-level cache saves the ObjectFactory instance corresponding to A. Then the method will be called to assign a value to this instance. At this time, since A depends on B, the method will be called again in the container. Try to get instance B. Since B has not been created yet, the method will be called recursively. doCreateBeancreateBeanInstance
Insert image description here
addSingletonFactory
Insert image description here
populateBean
Insert image description here
populateBeangetBeandoCreateBean

IndoCreateBean, create instance B throughcreateBeanInstance, and put its corresponding factory, that is, ObjectFactoryB, into the third-level cache. At this time The third-level cache stores the respective ObjectFactory instances of instance A and instance B.

will then call the populateBean method in B. At this time, our B depends on A, so it will be called again in populateBean The a>getBean method attempts to obtain an A instance.
At this time, since AbstractBeanFactory is called doGetBean, this method will try to call the getSingleton method to obtain A from the third-level cache. The instance
Insert image description here
Insert image description here
can be obtained at this time, then the ObjectFactory instance will be taken out and the getObject method area inside will be called to obtain the instance of A.
HeregetObject is actually calling the method in doCreateBean to obtain the post-processor A instance after processing. Then after obtaining: , the A instance will be put into the second-level cache, and the A instance in the third-level cache will be cleared, and then it will be A instance returns. At this time, the execution reaches here: Then, since the A instance is obtained when the B instance executes , it also At this time, the A instance is injected into B. When B finishes executing, A has been obtained. B will execute the remaining logic and obtain a complete Bean instance. getEarlyBeanReference
Insert image description here

Insert image description here


Insert image description here
populateBeanpopulateBean

And since the doCreateBean method is called by the doGetBean method, it will return the complete Bean instance of B to layer by layer. doGetBean method.
We go to doGetBean:
Insert image description here
Since doGetBean is called createBean, and then calldoCreateBean.
Our doCreateBean is executed when is called in the getSingleton method. It is worth noting that the here is not the same as the method mentioned above that attempts to obtain a Bean instance from the third-level cache. the same one. singletonFactory.getObject()
Insert image description here
getSingletongetSingleton

In this method, the addSingleton method will eventually be called:
Insert image description here
In the addSingleton method:
Insert image description here
Instance B will eventually be added to the first-level cache.
and remove the B instance from the second-level and third-level caches, indicating that the creation of B's ​​Bean instance has been completely completed.

And then return the complete Bean instance of B.

And because the creation of B is triggered by the A instance calling populateBean, it will return to A's populateBean method.
Insert image description here
Previously, B was assigned to the complete A. Here, A is assigned to the complete B, so both A and B are complete.
At this time, it will return to the doGetBean method, and then call addSingleton to put the A instance into the first-level cache. .
Insert image description here
Insert image description here
At this time, instance A will be placed in the first-level cache, and the second-level cache and third-level cache of instance A will be cleared.
This completes support for circular dependencies.

This may sound a bit confusing. Let’s summarize it through the following picture:
Insert image description here
When instance A is created for the first time, addSingletonFactory will be called. Put the ObjectFactory instance corresponding to the A instance into the third-level cache, and then call populateBean to assign the attribute B to our A instance. Then when assigning the value, we will find that B does not exist, so it will Call the getBean method to obtain the Bean instance corresponding to B.

The same is true for B instance at this time. First inject the ObjectFactory instance where B instance is located into the third-level cache, and then call the populateBean method to assign a value to the A attribute in B. At this time The getBean method will be called again to obtain the A instance. Because the ObjectFactory corresponding to A has been previously placed in the third-level cache, it can be obtained from the third-level cache at this time. The ObjectFactory instance corresponding to A, and then call the ObjectFactory's getObject method to obtain the instance of A.

After obtaining the instance of A, you can inject the instance of A into B, and then complete the creation of B. Then the instance of B will be placed in the first-level cache, and other level caches will be cleared, and then its instance will be returned to A. After that, The creation of A is completed, A is also placed in the first-level cache, and the instances in other level caches are cleared, thus completing the creation of two interdependent singletons.

Spring’s support for circular dependencies

In general, Spring will have the following two circular dependency situations:

  • Constructor circular dependency (singleton, prototype)
  • Setter injects circular dependencies (singleton, prototype)

For prototype, Spring does not support related circular dependencies by default.
Because the key to solving circular dependencies depends on the third-level cache of singletons. In addition to solving circular dependencies, the third-level cache also solves the problem of maintaining the uniqueness of singletons.
Because the Bean instance taken out from the cache must be unique, the third-level cache cannot support prototype. After all, the Bean instance of prototype is not unique, which is why prototype is not used. The third level cache is just the reason why the name is put into the cache.

And it is precisely because there is no support for third-level cache that the prototype does not support dependency cycles.

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

Spring only supports circular dependencies of Setter's singleton.

Guess you like

Origin blog.csdn.net/qq_45455361/article/details/121434977