= = =

shadow? sThe 2019-10-21 19:27:40 19396 Collection of 134

Spring source code analysis Spring 5 Architect

copyright

If you want to systematically learn spring source code then the first need to understand the knowledge of spring is the BeanDefinition – Spring bean modeling object;

The author especially emphasizes that beanDefintion is boring and difficult to understand, but it is very, very important. I plan to write three articles to finish the knowledge of beanDefintion. If you want to peruse spring source code, be sure to peruse three beanDefintion articles. BeanDefintion is a cornerstone of the Spring Framework.

So what are the modeling objects for Spring beans? Basically a model object that instantiates a bean? Spring can’t instantiate a bean with a Class object. Spring can’t instantiate a bean with a Class object. Spring can instantiate a bean with a Class object. Simply because a Class cannot abstract beans, such as the scope of the bean, the injection model of the bean, whether the bean is lazily loaded, etc., the Class cannot be abstracted. Therefore, a BeanDefinition Class is required to abstract this information. So that Spring can instantiate a bean perfectly (see my first circular reference article on what a bean is and what an object is).

A Class can be used to describe attributes and methods of a Class and so on. BeanDefintion can be used to describe scopes, lazy, As well as properties and methods and other information

A diagram illustrates the basic process of instantiating an object in Java



If we have N.java files on disk, we will first compile these Java files into class files, and then the Java virtual machine will load these class files into memory. When the new keyword is encountered, the object will be instantiated based on the template information of the class, that is, the heap is allocated memory

However, spring’s bean instantiation process is different from that of a normal Java object, again illustrated in a diagram

I will elaborate on this diagram at length. In the springbean instantiation diagram, I have marked a total of steps (5); Let’s go through them one by one

Premise: Suppose you have two classes X and Y on your project or disk. X is annotated with Spring and Y is not annotated with Spring. GetBean (Y) returns a bean of X (X) when the spring container starts, but getBean(Y) returns an exception because Y cannot be scanned by the Spring container and cannot be instantiated properly.

(1) [^ 1] when the spring container start to call ConfigurationClassPostProcessor scan post processor is complete, the bean factory about what is the bean factory rear processors below again to explain in detail; The detailed source code that Spring does the scanning will be covered in a future article. To read this article, you only need to know exactly what the scan does; In fact, the so-called Spring scan is to read the information of the class, but read the information of the class to store? The type of the class, the name of the class, the constructor of the class. Some readers may wonder if this information needs to be stored directly in the class object. Class clazzx = x.class; This is true, but spring not only needs this information to instantiate a bean, but also needs to store the scope, lazy, dependsOn, etc I mentioned above. So Spring designed a BeanDefintion class to store this information. Therefore, when Spring reads the class information, ②[2] instantiates a BeanDefinition object, and then calls the various set methods of this object to store the information. For each class that matches the rule, Spring instantiates a BeanDefinition object and generates a bean name based on the class name (e.g., IndexService, Spring generates a bean name ‘IndexService’ based on the class name IndexService. Spring has a default name generation rule, but programmers can provide their own name generators to override spring’s built-in name generators, which will be updated later.) [3] Spring then puts the beanDefinition object and the generated beanName into a map, key=beanName, value=beanDefinition object; Steps ①, ②, and ③ in the figure above are completed.

It’s important to note that Spring does a lot of work when it starts up, not only to complete the scan, but also to do a lot of other things before the scan; Examples such as instantiating beanFacctory, instantiating class scanners, etc., are not discussed here but will be discussed in a future article

Prove the above theory with a piece of code and results

Appconfig.java @ComponentScan("com.luban.beanDefinition") @Configuration public class Appconfig { } X.java @Component public class X { public X(){ System.out.println("X Constructor"); } } Y.java public class Y { } Test.java public class Test{ public static void main(String[] args) { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(); ac.register(Appconfig.class); ac.refresh(); }} 123456789101112131415161718192021222324252627Copy the code

There are two classes X and Y in the code above (see screenshots of the code I ran below), X is annotated, Y is not, and there is a constructor in X that prints once X is instantiated"X Constructor"; And it’s printed at the beginning of the main method"start"According to the author’s theory above, Spring will first scan X and then parse X as a beanDefinition object into the map; Author in Spring source codeorg.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessorsMethod has a breakpoint (invokeBeanFactoryPostProcessorsMethod, which prints when the application startsstart, then start the Spring container, and callinvokeBeanFactoryPostProcessorsMethod before the method is executedbeanDefintionMapThere is no element with key “x” in it, indicating that x is not scannedinvokeBeanFactoryPostProcessorsMethod to check againbeanDefintionMapYou can see that there is an element with key “x” in the map, and its corresponding value is a beanDefintion object. Finally, you can check the background and find that it has not been printed"X Constructor"This shows that X is not instantiated at this time. This example shows that Spring first scans out the class and parses it as a beanDefintion object and then puts it intobeanDefintionMapI’m going to instantiate X later, but this onebeanDefintionMapI’ll cover this in more detail in a later article, but you just need to know that it’s a collection of BeanDefinitions

④ After Spring stores the beanDefintion object corresponding to the class into the map, Spring calls the bean factory post-processor provided by the programmer. What is bean factory post-processor? At the spring code level, there is an interface to represent BeanFactoryPostProcessor. Once implemented, this interface is a bean factory postprocessor. Here’s the basic function. The BeanFactoryPostProcessor interface is also implemented inside Spring, such as the class that does the scanning in step 1ConfigurationClassPostProcessorSpring is a bean factory backend processor implemented by Spring itself, which I think is read in spring source codeThe most importantClass, none of which; He completed too many functions, later we will analyze one by one, first take a look at the class structure diagram of this class.



ConfigurationClassPostProcessorMany interfaces are implemented, but only two are relevant for this articleBeanDefinitionRegistryPostProcessorandBeanFactoryPostProcessor; But because theBeanDefinitionRegistryPostProcessorIs inheritedBeanFactoryPostProcessorSo you can understand that this is one interface, but I recommend that you think of it as two interfaces because spring does steps ①, ②, and ③ aboveBeanDefinitionRegistryPostProcessorthepostProcessBeanDefinitionRegistryMethod, spring executes at step 4BeanFactoryPostProcessorthepostProcessBeanFactoryMethods; What spring does is call the function ①②③ConfigurationClassPostProcessortheBeanDefinitionRegistryPostProcessorthepostProcessBeanDefinitionRegistryMethod, which spring will call first at step 4ConfigurationClassPostProcessortheBeanFactoryPostProcessorthepostProcessBeanFactoryAnd then call the one provided by the programmerBeanFactoryPostProcessorthepostProcessBeanFactoryMethod, so step 4 in the figure above I draw a red dotted line, because step 4 May not (if the programmer does not provide his own)BeanFactoryPostProcessor; Of course, it must be stated here, even if the programmer does not provide his own extensionBeanFactoryPostProcessor, Spring also executes the built-inBeanFactoryPostProcessorThat isConfigurationClassPostProcessor, so the drawing is not standard, missing a step; The spring implementation is built inBeanFactoryPostProcessor;

Key points: In our own words, we summarize BeanFactoryPostProcessor’s execution timing (whether built-in or provided by programmers) ———— ⅰ : If a class implements BeanFactoryPostProcessor directly, it does so after Spring has finished scanning the class (which involves turning it into a beanDefinition and putting it into a Map) and before instantiating the bean (step 5). Ⅱ if realize BeanDefinitionRegistryPostProcessor interface classes; Admittedly, this is also called a Bean factory postprocessor. It executes at the same time as the scan (steps ①, ②, ③ above), before executing the classes that directly implement the BeanFactoryPostProcessor. If your application extends a function, you can implement this interface if you need to do some function at this time; However, the author has not met such demand so far. If you meet or see it in the future, you can make it up. (explain when I published this blog have a reader to contact the author said that he saw a mainstream framework is the extension of BeanDefinitionRegistryPostProcessor class, in an instant the author such as the long drought meet showers, bachelor of widows; Hence immediately consult; The reader said that the latest code of Mybatis is to extend this class to achieve, I remember mybatis is not used in the extension of this interface, then I have a look at the latest mybatis source code is exactly what the reader said, in the next article I analyze the mainstream framework how to extend spring update.)

Here again, this paragraph is boring and obscure, but very important, if you want to do a close reading of spring source code this paragraph is particularly important, I recommend readers to read and understand;

So what does the BeanFactoryPostProcessor provided by the executive programmer mentioned in step 4 mean? Where are the scenarios where programmers provide BeanFactoryPostProcessor? What major frameworks have done this?

To answer the first question, what’s the point? Take a look at the method signature of this interface

void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) 
throws BeansException;
12
Copy the code

To discuss this method is to discuss the function or meaning of BeanFactoryPostProcessor, refer to the javadoc of this method

Modify the application context’s internal bean factory after its standard initialization

Combined with the execution timing of this method and the javadoc, we can understand the bean factory postprocessor (we are only talking about postprocessors that directly implement BeanFactoryPostProcessor, Does not include the post processor to realize BeanDefinitionRegistryPostProcessor) is actually spring provides an extension point (spring provides a lot of extension points, study the spring source is a very important reason why to learn these extension points, In order to redevelop Spring or write elegant plug-ins), allowing programmers to intervene in the bean factory initialization process. The most important words in this sentence are initialization, not initialization

Instantiation process

; There is a big difference between initialization and instantiation, especially when reading Spring source code. If you look at the Spring source code, you will find that the entire container initialization process is spring’s various post-processor calls; There are roughly two types of post-processor; One is the instantiation post-processor and one is the initialization post-processor, and this is not a conjecture, but if you are familiar with spring’s post-processor architecture you can see from the name of spring’s post-processor that there is a very big distinction between initialization and instantiation.

In plain English, beanFactory is instantiated and BeanFactoryPostProcessor does not intervene. However, after the beanFactory New comes out, various attributes can be filled or modified (initialized) through the BeanFactoryPostProcessor. You can see the only way to the spring BeanFactoryPostProcessor postProcessBeanFactory there is only one parameter in a standard the beanFactory object – ConfigurableListableBeanFactory; Since Spring passes in the instantiated beanFactory object when it calls the postProcessBeanFactory method, it’s only natural that we can do whatever we want with the beanFactory;

While being reckless sounds cool, many people are confused. It’s like getting you an Audi A6 (my dream Car! It tells you that you can do whatever you want with the car, but if you only know how to honk the horn, you are not doing the giver a favor. In fact, you have no idea that you can drive this car to Changsha’s Liberation West Road in the middle of the night to turn around, and then receive a lot of unexpected “love”; I use this example to say that when you get a beanFactory object, you can’t just sout, that’s not reckless; We can do a lot of things, but you have to understand the features of beanFactory or the various apis of beanFactory, but the beanFactory object is too complex to discuss here, For the sake of this article, just know that the beanDefintionMap (the collection that stores beanDefintion) we mentioned above is defined in the beanFactory; It also provides apis for programmers to manipulate the map, such as modifying the beanDefinition object in the map or adding a beanDefinition object to the map. Look at a piece of code

@Component public class TestBeanFactoryPostPorcessor implements BeanFactoryPostProcessor { @Override public void PostProcessBeanFactory (ConfigurableListableBeanFactory the beanFactory) throws BeansException {/ / into subclasses, Because the parent class didn't add beanDefintion object API DefaultListableBeanFactory defaultbf = (DefaultListableBeanFactory) the beanFactory; GenericBeanDefinition Y = new GenericBeanDefinition(); y.setBeanClass(Y.class); / / add a beanDefinition object, originally this Y is not spring scanning to defaultbf. RegisterBeanDefinition (" Y ", Y); / / get a beanDefintion object has been scanned by x / / because x would be scanned out, so is directly obtained from the map BeanDefinition x = defaultbf. GetBeanDefinition (" x "); // Change the class of the beanDefintion object of X to Z // the class of the original X to x.class; Now for the Z.c lass x.s etBeanClassName (" com. Luban. BeanDefinition. Z "); }} 1234567891011121314151617181920212223Copy the code

There are three classes X, Y, and Z in the project. Only X has the @Component annotation; That is, when the code executes to the method above, only X is scanned; BeanDefinitionMap in beanFactory also has only beanDefinition objects corresponding to X; I call registerBeanDefinition(” Y “, Y); Put the beanDefinition object corresponding to y to the beanDefinitionMap. This demonstrates the dynamic addition of a beanDefinition object instantiated by yourself; GetBeanDefinition (“x”) gets an existing beanDefinition object, and x.setBeanClassName(“Z”); The class of the beanDefinition object corresponding to x has been changed to Z, demonstrating the dynamic modification of a Scanned beanDefinition object.

The test code is as follows:

public static void main(String[] args) { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(); ac.register(Appconfig.class); ac.refresh(); // Print system.out.println (ac.getbean (y.class)); Println (ac.getbean (z.lass)); // Print system.out.println (ac.getbean (z.lass)); System.out.println(ac.getbean (x.lass))); } 12345678910111213Copy the code

The appended drawings:

To summarize the above diagram, spring instantiates a bean not directly related to the class you provide, but to the class that a beanDefinition corresponds to (normally a beanDefinition corresponds to a class, but not always); To make A vulgar analogy, say the reader you like A girl little A; And little A likes the author, but you can’t say you like the author too; And I’m a straight man of steel who can’t be bent anyway;

After reading this result, do you dare to belittle spring’s modeling object beanDefintion? However, the BeanDefinition interface has too many implementation classes, which is a complicated embodiment. In the next article, I will slowly introduce the various BeanDefinition objects embodied in Spring one by one.

So what does the BeanFactoryPostProcessor provided by the executive programmer mentioned in step 4 mean? Where are the scenarios where programmers provide BeanFactoryPostProcessor? What major frameworks have done this? We answered the first question roughly. Programmers typically provide BeanFactoryPostProcessor to modify or interfere with beanFactory initialization. What can I change? Or interfere with what? This problem is quite big. At least now you know that you can modify beanDefinitionMap in beanFactory. As for the remaining two questions, I will update them later