Spring framework source code analysis

Table of contents

Understanding of spring

Advantages of Spring

What is an IOC

The underlying implementation principle of Spring's AOP

bean life cycle

How to resolve circular dependencies

Why is L3 cache needed?

What are the functions of the third-level cache

Several scopes are supported in Spring

The difference between Bean Factory and FactoryBean

What design patterns are used in the Spring framework 

singleton pattern

prototype pattern

template pattern

Observer pattern

factory pattern

adapter pattern

decorator pattern

Proxy mode

strategy pattern

chain of responsibility default

Delegator pattern

The implementation principle of how Spring's transaction rolls back the transaction

Transaction Propagation Behavior Transaction Annotation Attributes

What types of advice are there in Spring (Advice)


Understanding of spring

Spring has developed from the simple xml configuration method to the current annotation-based programming method.

  Spring is a lightweight IoC and AOP container framework. It is a set of frameworks that provide basic services for Java applications. The purpose is to simplify the development of enterprise applications. It allows developers to only care about business needs. There are three common configuration methods: XML-based configuration, annotation-based configuration, and Java-based configuration.

It mainly consists of the following modules:

  • Spring Core : core class library, providing IOC services;
  • Spring Context : Provide framework-style Bean access methods, as well as enterprise-level functions (JNDI, scheduled tasks, etc.);
  • Spring AOP : AOP service;
  • Spring DAO : The abstraction of JDBC simplifies the handling of data access exceptions;
  • Spring ORM : support for existing ORM frameworks;
  • Spring Web : Provides basic web-oriented comprehensive features, such as multi-party file upload;
  • Spring MVC : Provides a Model-View-Controller implementation for web applications.

Advantages of Spring

 

What is an IOC

Understanding of SpringIOC module:

Inversion of control: theoretical thinking, the original object is controlled by the user, with spring, the entire object can be handed over to spring to help us manage

​DI: Dependency Injection, injecting the value of the corresponding attribute into a specific object, @Autowired, populateBean completes the injection of the attribute value

Container: store objects, use the map structure to store, generally there is a three-level cache in spring, singletonObjects store complete bean objects,

​The entire bean life cycle, from creation to use to destruction, is all managed by the container ( bean life cycle )

        1. First create a Bean factory (DefaultListableBeanFactory) through createBeanFactory

        2. Start to create objects in a loop, because the beans in the container are singletons by default, so first search for them from the container through getBean and doGetBean, if they cannot be found,

        3. Through the createBean and doCreateBean methods, objects are created in a reflective manner. Generally, the no-parameter construction method (getDeclaredConstructor, newInstance) is used

        4. Fill the populateBean with the properties of the object

        5. Perform other initialization operations (initializingBean)

The underlying implementation principle of Spring's AOP

Aop is an extension function of ioc. The first ioc and then aop are just a new extension point in the whole process of ioc: BeanPostProcessor

There is a step in the bean creation process that can extend the bean. AOP itself is an extension function, so it is implemented in the post-processing method of BeanPostProcessor

1. The process of creating proxy objects (advice, facet, point cut)

2. Generate proxy objects through jdk or cglib

​ 3. When the method call is executed, it will be called into the generated bytecode file, and the intercept method in the DynamicAdvisoredInterceptor class will be found directly, and execution will start from this method

4. Generate the interceptor chain according to the previously defined notification

5. Obtain each notification in turn from the interceptor chain and start executing. In the execution process, in order to find out which notification is next, there will be a CglibMethodInvocation object. When looking for it, it starts from the position of -1 once. and executed.

 

bean life cycle

1. Instantiate bean: generate objects by reflection

2. Populate the properties of the bean: populateBean(), the problem of circular dependency (three-level cache)

3. Call the method related to the aware interface: invokeAwareMethod (complete the property setting of the BeanName, BeanFactory, and BeanClassLoader objects)

4. Call the pre-processing method in BeanPostProcessor: there are more used (ApplicationContextPostProcessor, setting ApplicationContext, Environment, ResourceLoader, EmbeddValueResolver and other objects)

5. Call the initmethod method: invokeInitmethod(), judge whether the initializingBean interface is implemented, if so, call the afterPropertiesSet method, if not, do not call

6. Call the post-processing method of BeanPostProcessor: spring's aop is implemented here, AbstractAutoProxyCreator

​ Register the callback interface related to Destuction: hook function

7. Get the complete object, you can get the object through getBean

8. Destruction process, 1; determine whether the DispoableBean interface is implemented, 2, call the destroyMethod method

How to resolve circular dependencies

Circular dependencies:

        1. First create the A object and instantiate the A object. At this time, the b attribute in the A object is empty, and the attribute b is filled.

        ​ 2. Find the B object from the container. If you find it, there is no circular dependency problem (no way) in the direct assignment, and you can't find the B object directly.

​ 3. Instantiate the B object. At this time, the a attribute in the B object is empty, and the attribute a is filled.

4. Find the A object from the container, if you can't find it, create it directly

If you observe carefully, you will find that the A object exists, but at this time the A object is not a complete state, only the instantiation has been completed but the initialization has not been completed. If there is a reference to an object during the program call , can you complete the assignment operation for him in the later stage, you can give priority to the assignment of incomplete state objects, and wait for subsequent operations to complete the assignment, which is equivalent to exposing a reference to an incomplete object in advance, so the core of solving the problem lies in instantiation It is operated separately from initialization, which is also the key to solving the circular dependency problem.

​ After all the objects have been instantiated and initialized, the complete object must be placed in the container. At this time, there are several states of the object in the container. Completed instantiation = but not completed initialization, complete state, because all In the container, different map structures are used for storage. At this time, there is a first-level cache and a second-level cache. If there is one in the first-level cache, then there will be no object with the same name in the second-level cache, because Their search order is 1, 2, 3 to search in this way. The first-level cache stores complete objects, while the second-level cache stores incomplete objects.

​ Why do we need a third-level cache? The value type of the third-level cache is ObjectFactory, which is a functional interface . The meaning of existence is to ensure that there can only be one bean object with the same name during the running of the entire container .

​ If an object needs to be proxied, or a proxy object needs to be generated, should a normal object be generated first? Ordinary objects and proxy objects cannot appear in the container at the same time, so when an object needs to be proxied, it is necessary to use the proxy object to overwrite the previous ordinary object. In the actual call process, there is no way to determine when the object It is used, so when an object is called, it is required to first judge whether the object needs to be proxied, which is similar to the implementation of a callback mechanism, so when the lambda expression is passed in, the object can be executed through the lambda expression Override process, getEarlyBeanReference()

​ Therefore, all bean objects should be placed in the third-level cache first when they are created . In the subsequent use process, if they need to be proxied, they will return the proxy object. If they do not need to be proxied, they will directly return the normal object.

Cache placement time and deletion time:

Level 3 cache: after createBeanInstance: addSingletonFactory

​ Second-level cache: When determining whether the object is a proxy object or a normal object from the third-level cache for the first time, delete the third-level cache getSingleton at the same time

​ Level 1 cache: After generating a complete object, put it in the level 1 cache, delete the second and third level caches: addSingleton

Why is L3 cache needed?

The third-level cache mainly deals with AOP proxy objects, which store an ObjectFactory

The third-level cache considers bringing your objects, while the second-level cache considers performance-creating objects from the factory in the third-level cache, and then throwing them into the second-level cache (so that you don’t have to take them from the factory every time)

What are the functions of the third-level cache

Level 1 Cache: Formal Objects

Second-level cache: semi-finished objects

L3 cache: factory

 

Several scopes are supported in Spring

Beans in the Spring container can be divided into 5 scopes:

        prototype: Provide an instance for each bean request.

        singleton: By default, there is only one bean instance in each container, and the singleton mode is maintained by BeanFactory itself.

        request: An instance is created for each network request. After the request is completed, the bean will be invalidated and reclaimed by the garbage collector.

        session: Similar to the request scope, ensure that there is an instance of a bean in each session. After the session expires, the bean will become invalid.

        global-session: Global scope, global-session is related to Portlet application. When your application is deployed to work in a portlet container, it contains many portlets. If you want to declare a global storage variable for all portlets, then this global variable needs to be stored in global-session. The global scope has the same effect as the session scope in Servlet.

 

The difference between Bean Factory and FactoryBean

When using BeanFactory to create objects, you must follow the strict life cycle process, which is too complicated. If you want to simply customize the creation of an object, and the created object wants to be managed by spring, then you need to implement FactroyBean interface

​ isSingleton: Whether it is a singleton object

​ getObjectType: Get the type of the returned object

​ getObject: Customize the process of creating objects (new, reflection, dynamic proxy)

What design patterns are used in the Spring framework 

singleton pattern

  The singleton pattern should be the most impressive design pattern. The most obvious usage scenario in Spring is to set the scope value to singleton when configuring the registration bean object in the configuration file  .

prototype pattern

  Prototype mode is also called clone mode. This mode is obviously used in Spring. Like a single case, setting the scope attribute prototype in the bean tag means that the bean is generated by cloning.

template pattern

  The core of the template mode is that the parent class defines the process, and then abstracts the methods that need to be implemented by the subclass in the process to the subclass for implementation. JdbcTemplate in Spring is such an implementation. We know that the steps of jdbc are fixed

  • load the driver,
  • get connection channel,
  • Build the sql statement.
  • execute sql statement,
  • close resource

  In these steps, the third and fourth steps are uncertain, so it is left to the customer to implement, and when we actually use JdbcTemplate, we really only need to build SQL. This is a typical template mode.

Observer pattern

  The observer pattern defines a one-to-many dependency relationship between objects. When the state of an object changes, all objects that depend on it are notified and automatically updated. The usage comparison scenario is in the listener, and the commonly used place for the Observer pattern in spring is also the implementation of the listener. Such as ApplicationListener.

factory pattern

Simple factory pattern :

  The simple factory pattern is to use the factory to determine which object to generate according to the parameters passed in. In Spring, when we get an object through the getBean method, it is a simple factory pattern to get it by id or name.

 

Factory method pattern :

  In Spring, we generally hand over the instantiation of beans directly to the container to manage, realizing the separation of use and creation. At this time, the container directly manages the object. In another case, we hand over the bean creation process to a factory. implementation, and the Spring container manages this factory. This is the factory pattern we are talking about. There are two implementations in Spring, one is the static factory method pattern and the other is the dynamic factory method pattern.

adapter pattern

  Convert the interface of a class to another interface that the client wants. Allows classes that would otherwise not work together due to incompatible interfaces to work together. This is the adapter pattern. The conversion between Advice and interceptor in AOP implementation in Spring is realized through adapter mode.

decorator pattern

  Decorator mode, also known as wrapper mode (Wrapper), is used to dynamically add new functions to an object. Decoration mode is a technology used to replace inheritance, and new functions of objects can be extended without adding subclasses through inheritance. It is more flexible to use the association relationship of objects instead of the inheritance relationship, while avoiding the rapid expansion of the type system.
  The wrapper pattern used in spring has two manifestations in the class name: one is that the class name contains Wrapper, and the other is that the class name contains Decorator. Basically, add some additional responsibilities to an object dynamically.
  Specifically, the SessionRepositoryRequestWrapper used in the Spring session framework uses the packaging mode to enhance the function of the original request, and can synchronize the data in the session with the distributed database, so that even if the current tomcat crashes, the data in the session will not be lost.

Proxy mode

  The proxy mode should be a design mode that everyone is very familiar with. The proxy mode is used very thoroughly in the implementation of AOP in Spring.

strategy pattern

  The strategy pattern corresponds to an algorithm family for solving a certain problem, allowing users to choose an algorithm from the algorithm family to solve a certain problem, and at the same time, it is convenient to replace the algorithm or add a new algorithm. And it is up to the client to decide which algorithm to call. The Strategy mode is used in spring when instantiating objects. XmlBeanDefinitionReader, PropertiesBeanDefinitionReader

chain of responsibility default

Interceptor chain in AOP

Delegator pattern

DelegatingFilterProxy is used when integrating Shiro and SpringSecurity.

The implementation principle of how Spring's transaction rolls back the transaction

The transaction of spring is realized by aop. First, a specific proxy object must be generated, and then the specific operation logic should be executed according to the whole process of aop. Under normal circumstances, the core function should be completed through notification, but the transaction is not realized through notification. , but through a TransactionInterceptor, and then call invoke to implement specific logic.

1. Do the preparatory work first, analyze the transaction-related attributes of each method, and judge whether to start a new transaction according to the specific attributes

​ 2. When it needs to be opened, obtain the database connection, close the automatic submission function, and start the transaction

3. Execute specific sql logic operations

​ 4. During the operation, if the execution fails, the transaction rollback operation will be completed through completeTransactionAfterThrowing. The specific logic of the rollback is realized through the doRollBack method. When implementing it, the connection object must be obtained first, through connect object to rollback

5. If there is no unexpected situation during the execution process, then the commit operation of the transaction is completed through commitTransactionAfterReturning. The specific logic of the commit is realized through the doCommit method. When it is realized, it is also necessary to obtain the connection and submit it through the connection object

6. After the transaction is executed, the relevant transaction information needs to be cleared cleanupTransactionInfo

Common annotations for transactions:

REQUIRED -- support the current transaction, if there is no current transaction, create a new transaction. This is the most common choice. 

SUPPORTS -- support the current transaction, if there is no current transaction, it will be executed in a non-transactional manner. 

MANDATORY -- supports the current transaction, and throws an exception if there is no current transaction. 

REQUIRES_NEW -- create a new transaction, if there is a current transaction, suspend the current transaction. 

NOT_SUPPORTED -- perform operations in a non-transactional manner, and suspend the current transaction if there is a current transaction. 

NEVER -- Execute in a non-transactional manner, throwing an exception if a transaction currently exists. 

NESTED -- Execute within a nested transaction, if a transaction currently exists. If there is no transaction currently, perform a similar operation to REQUIRED. 

Transaction Propagation Behavior Transaction Annotation Attributes

 

What types of advice are there in Spring (Advice)

        Before Advice: Before - These types of Advice are executed before joinpoint methods and are configured using the @Before annotation tag.
        After Returning Advice: After Returning - These types of advice are executed after the normal execution of the join point method and are configured using the @AfterReturning annotation marker.
        Exception notification: After Throwing - These types of Advice are only executed when the joinpoint method exits by throwing an exception and is configured with the @AfterThrowing annotation mark.
        Final Advice: After (finally) - These types of Advice are executed after the join point method, regardless of whether the method exits normally or abnormally, and are configured using the @After annotation marker.
        Around Advice: Around − These types of Advice are executed before and after a join point and are configured using the @Around annotation tag.

 

Guess you like

Origin blog.csdn.net/weixin_43195884/article/details/128954915