Spring overall architecture analysis

I. Introduction

I have not used spring for a long time, nor have I read the source code in depth, but because I recently learned about the following spring source code, I want to use my own understanding to describe spring, so there may be inappropriate places. If someone reads and finds Error, hope to remind! !

We know that the two most important concepts of spring are Ioc and Aop, which run through the use of spring.
The spring framework has a very important role, that is, the bean.

Everything is derived from bean

  1. Where is the source of the bean?
  2. What if you create a bean?
  3. What structure is used to store beans?
  4. What is used to manage all the beans?

Let's talk about the bean source first

People who have used spring have written such code more or less

<bean id=? class=? scope init-method abstract>
    <propety name=? value=?/>
	<propety name=? ref=?/>
</bean>

<bean id=? class=? scope init-method abstract>
    <constructor-arg name=? value=?/>
	<constructor-arg name=? ref=?/>
</bean>

That is, the objects you define in the xml file. This is one of the sources of spring.
You may have used these annotations.

  • @Bean
  • @Controller
  • @Component

This is also a source of beans

Even we can manually load beans in the code, but it is possible, but not necessary. (Springboot)

/**
@Configuration
或
@Component
或
@Bean定义
**/
@Configuration
public class DefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    
    
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0) 
throws BeansException {
    
    

    }

    /**
     * 先执行postProcessBeanDefinitionRegistry方法
     * 在执行postProcessBeanFactory方法
     */
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) 
        throws BeansException {
    
    
        // 第一种 : 手动注入
        // 注册bean
        registerBean(registry, "hello", HelloWord.class);
        registerBean(registry, "helloWord", HelloWord.class);
    }
/**
注册bean
**/
 private void registerBean(BeanDefinitionRegistry registry, String name, Class<?> beanClass) {
    
    
        RootBeanDefinition bean = new RootBeanDefinition(beanClass);
        registry.registerBeanDefinition(name, bean);
    }
}

Of course, we can also set the source of the bean ourselves, but we need to implement the relevant interface and rewrite the methods inside.(beanDefinitionReader)

The role of BeanDefinitionReader is to read the content in the Spring configuration file and convert it to the data structure inside the IoC container: BeanDefinition.

https://zhuanlan.zhihu.com/p/107839916

So after we know the source of the bean, the problem comes again, how does spring help us create this object?

Let’s review the following, how many ways are there to create an object?

  1. new
  2. Through the factory
  3. By reflection

Obviously, spring creates objects for us through reflection. The general idea is to read bean source information, and then create objects through reflection. There are actually a few core codes for creating objects

//三种或Class对象的的方式
Class clazz = Class.forName("完全限定名");
Class clazz = 对象.getClass();
class clazz =.class;

//clazz.newInstance(); 官方不推荐我们使用这种方式创建对象
Constructor con = clazz.getDeclareConstructor();
Object object = con.newInstance();

We know that if a bean is created, it is indeed through reflection, but spring is definitely more than that simple to create an object, there are many processes in the middle, and what data structure is used to save the bean we created?

In fact, the most suitable one is the Map structure. In spring, the Class object is not stored directly, but through the beandefinitionobject, the information of the beans defined in the configuration file... is stored. So why can't Spring use Class to create beans? Very simple, because Class cannot complete the abstraction of beans, such as bean scope, bean injection model, whether the bean is lazy loading, etc., Class cannot be abstracted out, so A BeanDefinition class is needed to abstract this information so that spring can instantiate a bean perfectly.

Insert picture description here

In the spring source code, there are multiple data structures to cache the data related to the bean.

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry

private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);
private final Set<String> registeredSingletons = new LinkedHashSet(256);
  1. singletonObjects(ConcurrentHashMap)

Save the relationship between BeanName and the created bean instance, bean name->bean instance.

  1. singletonFactories(HashMap)

Save the relationship between BeanName and the factory that created the bean, bean name -> ObjectsFatory

  1. earlySingletonObjects(HashMap)

It also saves the relationship between BeanName and creating bean instances. The difference between singletonObjects and singletonObjects is that when a singleton bean is placed in earlySingletonObjects, the bean can be obtained through the getBean() method (although it is only an early object, namely Still in the process of creating. The purpose is to solve the problem of circular dependencies)

  1. registeredSingletons(LinkedHashSet)

Save all currently registered beans

What manages so many beans?

We know that in spring, there are many containers. We know that a container is a concept of space, which is generally understood as a place where objects can be placed. In the Spring container, it is usually understood as BeanFactory or ApplicationContext. We know that spring's IOC container can help us create objects. After the objects are handed over to spring, we don't need to manually new objects.

There are two ways to create objects, BeanFactory and ApplicationContext.

  • BeanFactory

BeanFactory adopts a factory design pattern, which is responsible for reading bean configuration documents, managing bean loading, instantiation, maintaining dependencies between beans, and being responsible for bean life cycle. BeanFactory does not initialize the object when parsing the configuration file, and only initializes the object when the object getBean() is used.

  • ApplicationContext (interface)

In addition to the functions that the BeanFactory can provide, ApplicationContext also provides more complete framework functions: internationalization support, aop, transaction, etc. The ApplicationContext initializes all the objects in the configuration file when parsing the configuration file. The getBean() method is just the process of obtaining objects, which ensures that the application does not need to wait for them to be created.

Understand Spring container, BeanFactory and ApplicationContext

Finally, how does Spring manage beans

Note: Here we take the application context management bean as an example.

For <bean id="airplane" class="spring.Airplane"/>example, when spring starts, it will create an application context container, and all beans are loaded when the application context container is created. The general process is that the application context object will be based on the configuration file path we passed in. Load this configuration file, and then parse the <bean> tag under the <beans> tag of the configuration file, and then parse each bean tag. At this time, it will be based on the properties we configured in the bean tag (here we only define the id And class) to instantiate a BeanDefinition for each bean, and put these BeanDefinition objects into a List<BeanDefinition> collection in the application context, and then loop through List<BeanDefinition> and pass the class value through reflection, Instantiate the bean, and finally maintain the instantiated bean in a map. The key of the map is the id of the bean, and the value of the map is the instantiated object of the bean. Finally, we can get the bean we want through the id, but Here is just a brief introduction to bean loading. The application context does more than that, as well as the maintenance of lazy-loaded beans and the maintenance of dependencies between beans (which is what we often call dependencies, in fact, through a Map<String, Set<String>> type ConcurrentHashMap to maintain) and so on.

Second, describe the above process through a diagram

Through the above explanation, we can roughly describe part of the core of spring.

Insert picture description here
Do you feel that there are a lot of blanks in the process from BeanDefintion to BeanFactory, which is unsightly?

Yes, there are other classes in this way, they have a common interface BeanFactoryPostProcessor, enhancer, can modify the information defined by the bean.

Maybe you have written code like this when using spring

 <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">   
 <property name="driverClassName">
      <value>${jdbc.driverClassName}</value>
 </property>   
 <property name="url">
     <value>${jdbc.url}</value>
 </property>   
  <property name="username">
     <value>${jdbc.username}</value>
 </property>   
 <property name="password">
     <value>${jdbc.password}</value>
 </property>   
</bean> 

Are you curious when this variable is replaced?
In fact, it is the retrograde replacement on the one just mentioned , and the data is replaced with the data in the properties. Now you understand BeanFactoryPostProcessorthe role, through which you can modify the information in BeanDefintion. As you can see PlaceholderConfigurerSupport, this class implements the above interface, and its role is to parse and ${}replace the data we set.

public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfigurer implements BeanNameAware, BeanFactoryAware {
    
    
    public static final String DEFAULT_PLACEHOLDER_PREFIX = "${";
    public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}";
    public static final String DEFAULT_VALUE_SEPARATOR = ":";
    protected String placeholderPrefix = "${";
    protected String placeholderSuffix = "}";
 	// ...
 }

So, add the picture above: (Of course, more than one BeanFactoryPostProcessor)

Insert picture description here

You may wonder, why is it so complicated to create an object, so it must be instantiated and then initialized before it becomes a complete bean object?

Let's first talk about what spring did during the instantiation and initialization process

  • Instantiation: Open up a space in the heap, the attributes are default values ​​(because we use the Ioc container, do not need to manually new, so the reference type is mostly null)
  • Initialization-complete the assignment operation to the attribute
  1. Fill in attributes, assign values
  2. Call the specific initialization method(例如,在xml文件中,<bean></bean>标签中的init-method)

Spring is a framework and has a very powerful ecology, which also shows that it is very extensible. So it provides some interfaces in the process of instantiating the bean and initializing the bean, so that we can do something in the process. In fact, this has Aopsomething to do with it.

Spring provides us with an interface BeanPostProcessor. Allows us to perform some operations before and after initializing the bean. We call it post processor

public interface BeanPostProcessor {
    
    

	//实例化、依赖注入完毕,在调用显示的初始化之前完成一些定制的初始化任务
    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    
    
        return bean;
    }

	//实例化、依赖注入、初始化完毕时执行
    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    
    
        return bean;
    }
}
  • The post processor postProcessorBeforeInitailizationmethod is called after bean instantiation, dependency injection and (例如:配置文件中bean标签添加init-method属性指定Java类中初始化方法、@PostConstruct注解指定初始化方法,Java类实现InitailztingBean接口)before custom initialization method
  • The post processor postProcessorAfterInitailizationmethod is called after bean instantiation, dependency injection and custom initialization methods

You can be understood as BeanPostProcessora bridge between the Ioc and Aop. Of course, there can be more than one BeanPostProcessor.

We continue to improve the picture above:

Insert picture description here
Spring is definitely more than this, he also extended a lot for us. For example,
the role of a listener listener: a listener is an ordinary java program that implements a specific interface. This program is specifically used to monitor method calls or property changes of another java object. When the above events occur on the monitored object, the listener This method will be executed immediately.
The life cycle of the bean can be monitored through the listener...

You can check the following blogs about the life cycle of the bean:

  1. https://blog.csdn.net/qq_35634181/article/details/104473308
  2. https://blog.csdn.net/lisongjia123/article/details/52091013?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-6.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-6.control
  3. https://www.cnblogs.com/zrtqsk/p/3735273.html

Continue to improve the above picture

Insert picture description here

Of course, this is still not complete, there are some classes, such asEnvironment

Environment:为了方便使用,在容器创建的时候提前将系统相关属性加载到StandarEnvironment对象中,方便后续使用

You can view the following in-depth understanding

The last step is to perfect our final picture

Insert picture description here

supplement:

When the above-mentioned spring container, said BeanFactory和ApplicationContext, showing above does not ApplicationContextoccur, I understand that, ApplicationContextbut in the BeanFactoryoutside and then set a layer, and provides a more feature-rich, in fact, it is always through BeanFactoryTo manipulate the bean. (This is just my understanding)

Summary: If you want to become a framework, the first thing you must consider is extensibility.
What extensibility does Spring provide?

  1. Add some functionality between object creation
  2. Add some functions before the container is initialized
  3. Issue different events at different stages to complete certain functions
  4. Abstract a bunch of interfaces to help expand
  5. Interface-oriented programming

Three, not too deep understanding

When you try to read the source code, many people tell you that AbstractApplicationContext类的refreshto start from the method, as long as you understand the method, you know most of the spring. First understand the general function of each method inside

    public void refresh() throws BeansException, IllegalStateException {
    
    
        synchronized(this.startupShutdownMonitor) {
    
    
            StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
            this.prepareRefresh();
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);

            try {
    
    
                this.postProcessBeanFactory(beanFactory);
                StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
                this.invokeBeanFactoryPostProcessors(beanFactory);
                this.registerBeanPostProcessors(beanFactory);
                beanPostProcess.end();
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                this.onRefresh();
                this.registerListeners();
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } catch (BeansException var10) {
    
    
                if (this.logger.isWarnEnabled()) {
    
    
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
                }

                this.destroyBeans();
                this.cancelRefresh(var10);
                throw var10;
            } finally {
    
    
                this.resetCommonCaches();
                contextRefresh.end();
            }

        }
    }
  • this.prepareRefresh();

    1. Set the startup time of the spring container
    2. Undo the closed state
    3. Active state
    4. Initialize property meta information initPropertySource()
    5. Attributes that must exist in the verification environment
  • ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();

    • Obtain a BeanFactory instance
  • this.prepareBeanFactory(beanFactory);

    • Make relevant settings for BeanFactory to prepare for subsequent use
    1. Set up the ClassLoader to load the Bean
    2. Set up the expression parser, etc.
  • this.postProcessBeanFactory(beanFactory);

    • Template method, let different spring containers customize and extend their own loading methods, the method body is empty
  • this.invokeBeanFactoryPostProcessors(beanFactory);

    • (It will jump to ConfigurationClassParser.doProcessConfigurationClassparsing various tags, @Beanetc.) After calling the factory, the processor processes and parses various Bean tags (@Configuration/@Import/@Bean/@SpringbootApplication), scans the Bean files, and parses them into Beans. The Beans here are only loaded into the spring container, because the spring container Lazy loading, these Beans are only loaded into the container without connection and initialization. When the program needs to use the Bean, the bean will be connected and initialized.
  • this.registerBeanPostProcessors(beanFactory);

    • Find BeanPostProcessorsthe bean that implements the interface in the container , set it to the properties of the BeanFactory, and finally call it when the bean is instantiatedBeanPostProcessors(bean的后置处理器)
  • this.initMessageSource();

    • Load internationalization information
  • this.initApplicationEventMulticaster();

    • Initialize event broadcaster, used for event publishing
  • this.onRefresh();

    • Template method: Let different spring containers customize and extend their own loading methods, the method body is empty
  • this.registerListeners();

    • Register the listener
  • this.finishBeanFactoryInitialization(beanFactory);

    • Instantiate all beans that have been registered but not instantiated in the BeanFactory (lazy loading does not need to be instantiated)
  • this.finishRefresh();

    • Initialize the life cycle processor and other related things

Fourth, let’s talk about the overall architecture and core technology of spring

  • The following is a good blog I found

https://blog.csdn.net/u010209217/article/details/80617310

Five, finally, the knowledge of spring interview frequently asked questions

The author hasn't got a deep understanding of spring, so the following questions are not fully understood. I will continue to learn the source code in the future to find out the answers to the following questions:

  1. What is the Spring framework and which modules are included in the Spring framework
  2. Advantages of Spring Framework
  3. What are Ioc and DI?
  4. Describe the initialization process of the following Spring Ioc container
  5. What is the difference between BeanFactory and FactoryBean? (I have already answered this question on my previous blog)
  6. Similarities and differences between BeanFactory and ApplicationContext
  7. The life cycle of Spring Bean?
  8. The realization principle of Spring Aop
  9. How does Spring manage transactions
  10. What are the different transaction propagation behaviors of Spring, and what are their functions? (This has also been recorded)
  11. What design patterns are used in Spring?
  12. How does Spring resolve circular dependencies?
  13. Bean scope
  14. What are the different and similar events in the Spring framework?
  15. What are the types of Spring notifications?
  16. Spring's automatic assembly

Mention: Spring is closely related to Spring boot and Spring Cloud, which you will learn later. Spring is the core and foundation.

Guess you like

Origin blog.csdn.net/saienenen/article/details/112861280