It is recommended to buy a spring source code in-depth analysis
A "SPRING Technology Insider: In-depth Analysis of SPRING Architecture and Design Principles"
Author:
Zhanian Link: https://www.zhihu.com/question/21346206/answer/83795226
Source: Zhihu
The copyright belongs to the author. For commercial reprints, please contact the author for authorization, and for non-commercial reprints, please indicate the source.
1. Basic 1. Understand
Java syntax 2. Understand
design patterns
2. Project foundation After the IoC container is satisfied, enter spring-core and spring-beans STEP1-10
Link : https://www.zhihu.com/question/21346206/answer/221808473
Source: Zhihu The
copyright belongs to the author. For commercial reprints, please contact the author for authorization, and for non-commercial reprints, please indicate the source.
Before reading the spring source code, two questions should be clarified:
1. Where is the entry to read the source code?
2. Pre-requisite knowledge to understand: IOC and AOP
1. Where do we start
1. Preparations: After downloading the spring source code on the official website, import it into Eclipse for easy query.
2. Open our project project using Spring, find the Web.xml website system configuration file, and find Spring's initialization information in it:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
As can be seen from the configuration information, the entry point we started is the ContextLoaderListener listener.
In the source code we find this class, its definition is:
public class ContextLoaderListener extends ContextLoader
implements ServletContextListener {
…
/**
* Initialize the root web application context.
*/
public void contextInitialized(ServletContextEvent event) {
this.contextLoader = createContextLoader();
if (this.contextLoader == null) {
this.contextLoader = this;
}
this.contextLoader.initWebApplicationContext(event.getServletContext());
}
...
}
This class continues the ContextLoader and implements the listener. The information loading configuration and initialization about Spring starts here. For other details, read another article to learn more.
2. About IOC and AOP
There are many related articles on the Spring IOC online that can be read, so what are the knowledge points we have learned from it?
1) IOC container and AOP aspect dependency injection is the core of Spring.
The IOC container provides convenience and basic services for developers to manage the dependencies between objects, in which the Bean Factory (BeanFactory) and the context (ApplicationContext) are the manifestations of IOC. BeanFactory is an interface class that only defines the most basic services provided by the container, while DefaultListTableBeanFactory, XmlBeanFactory, ApplicationContext, etc. are all concrete implementations.
interface:
public interface BeanFactory {
//Here is the escape definition of the factory bean, because if the object obtained by retrieving the IOC container using the name of the bean is the object generated by the factory bean,
//If you need to get the factory bean itself, you need to use the escaped name to retrieve it from the IOC container
String FACTORY_BEAN_PREFIX = "&";
//Here, according to the name of the bean, the bean instance is obtained in the IOC container. This IOC container is like a large abstract factory, and the user can get the required bean according to the name.
//In Spring, the difference between beans and ordinary JAVA objects is:
//Bean already contains the processing of our dependencies in the Bean definition information, and the Bean has been placed in the IOC container for management, and has its own life cycle
Object getBean(String name) throws BeansException;
//Here, the bean instance is obtained according to the bean name and Class type. The difference from the above method is that it will throw an exception: if the Class type of the bean instance obtained by the root name is different from the required one.
Object getBean(String name, Class requiredType) throws BeansException;
//Here provides a bean retrieval to see if there is a bean with this name in the IOC container
boolean containsBean(String name);
//Here, the bean instance is obtained according to the bean name, and at the same time, it is judged whether the bean is a single piece. When configuring, the default bean is configured as a single piece. If the single piece is not required, the user needs to mark it in the bean definition information. Come out, so that every time the IOC container receives the user's getBean request, it will generate a new Bean and return it to the customer - this is the prototype form
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
//Here to get the Class type of the bean instance
Class getType(String name) throws NoSuchBeanDefinitionException;
//The alias of the bean is obtained here. If it is retrieved according to the alias, its original name will also be retrieved
String[] getAliases(String name);
}
accomplish:
The implementation of XmlBeanFactory is like this:
public class XmlBeanFactory extends DefaultListableBeanFactory {
//Here defines a default bean definition reader for the container. In the use of Spring, the reading of bean definition information is part of the container initialization, but the implementation is separate from the container registration and dependency injection. , so that a flexible bean definition reading mechanism can be used.
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
//Here needs a Bean definition information of Resource type. The actual positioning process is completed by the Resource construction process.
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
//Use the reader in the initialization function to read the resource and get the bean definition information. This completes the loading and registration process of the entire IOC container for the Bean definition information
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws
BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
We can see some basic processes used by the IOC container:
如:DefaultListableBeanFactory
ClassPathResource res = new ClassPathResource("beans.xml");//Read the configuration file
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(res);
<noscript><img src="https://pic2.zhimg.com/50/v2-b8ed7b2867b6ccb85194848951791786_hd.jpg" data-rawwidth="600" data-rawheight="279" class="origin_image zh-lightbox-thumb" width="600" data-original="https://pic2.zhimg.com/v2-b8ed7b2867b6ccb85194848951791786_r.jpg"></noscript>
![](https://pic2.zhimg.com/50/v2-b8ed7b2867b6ccb85194848951791786_hd.jpg)
The code demonstrates the following steps:
1. Create an abstract resource for the IOC configuration file
2. Create a BeanFactory, here we use DefaultListableBeanFactory
3. Create a reader that loads the bean definition information, here XmlBeanDefinitionReader is used to load the XML form
The bean definition information is configured to BeanFactory
4. Read the configuration information from the defined resource location. The specific parsing process is completed by XmlBeanDefinitionReader.
This completes the entire process of loading and registering bean definitions. Our IoC container is set up.
To put it simply, when my system starts up, the actions that will be completed are
1. Obtain resource files by ResourceLoader, that is, various configuration files of beans
2. Loading the definition information of the configuration file by BeanDefintion
3. Use the BeanDefinitionRegistry interface to load the bean definition information and register it with the IOC container.
Note that the initialization of the IOC container and context generally does not include the implementation of bean dependency injection.
2) The process of AOP is not implemented in the process of registering beans.
We only see that the RuntimeBeanReference object is used as a record of dependency information when dealing with related bean properties.
On the premise that the IOC container has loaded the user-defined bean information, this dependency injection process is triggered when the user asks the IOC container for a bean for the first time, or we can control the lazy-init attribute in the bean definition information. To make the container complete the pre-instantiation of the bean - this pre-instantiation is also a process of completing dependency injection.
Let's explain the process:
1. The user wants to request the Bean from the IOC container.
2. The system first checks whether there is a bean of this name in the cache (go to each BeanFactory to find it)
3. If not, create a bean and perform dependency injection, and the request will be recorded.
Request Bean specific implementation:
The code entry is in the base class AbstractBeanFactory of DefaultListableBeanFactory:
public Object getBean(String name, Class requiredType, final Object[] args) throwsBeansException {
...
Object sharedInstance = getSingleton(beanName);//Go to the cache first
if (sharedInstance != null) {
...
if (containsBeanDefinition(beanName)) {
RootBeanDefinition mergedBeanDefinition = getMergedBeanDefinition(beanName, false);
bean = getObjectForBeanInstance(sharedInstance, name,mergedBeanDefinition);
}
else {
bean = getObjectForBeanInstance(sharedInstance, name, null);
}
}
else {
}
...
}
The specific implementation of injected Bean:
The specific bean creation process and dependency injection are in createBean, and this method is implemented in AbstractAutowireCapableBeanFactory:
protected Object createBean(String beanName, RootBeanDefinition
mergedBeanDefinition, Object[] args)
throws BeanCreationException {
// Guarantee initialization of beans that the current one depends on.
// Here, for all dependent beans of the current bean, it is determined that these identified beans can be obtained. If they have not been created, the createBean will be used by these IOCs.
// create these beans when getbean
if (mergedBeanDefinition.getDependsOn() != null) {
for (int i = 0; i < mergedBeanDefinition.getDependsOn().length; i++) {
getBean(mergedBeanDefinition.getDependsOn()[i]);
}
}
........
// This is where the bean object is instantiated, pay attention to this BeanWrapper class, which is the main encapsulation class for bean operations
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mergedBeanDefinition,args);
}
Object bean = instanceWrapper.getWrappedInstance();
......
//This populate method is where dependency injection is performed on the created bean instance, and the bean is injected using the propertyValue obtained during loadBeanDefinition.
if (continueWithPropertyPopulation) {
populateBean(beanName, mergedBeanDefinition, instanceWrapper);
}
//Here completes some initialization actions of the bean customized by the customer
Object originalBean = bean;
bean = initializeBean (beanName, bean, mergedBeanDefinition);
// Register bean as disposable, and also as dependent on specified "dependsOn"beans.
registerDisposableBeanIfNecessary(beanName, originalBean,mergedBeanDefinition);
return bean;
}
.........
}
This is part of the entire dependency injection process. The main role in this process is WrapperImp. This Wrapper is not a
A simple encapsulation of the bean object because it needs to process the information in the beanDefinition to iteratively handle dependency injection.
At this point, it is simple. I have a general understanding of IOC and AOP. I have a general impression of getting started first.