Small knowledge, big challenge! This paper is participating in theEssentials for programmers”Creative activities.
We have talked about the design and implementation of Spring IoC in general last time. The following is a detailed description of the initialization of the Spring IoC container. Initialization can be divided into three steps, namely BeanDefiniton Resource location, load and registration.
The Resource location
Just like finding a source for water in a bucket, our first step in using an IoC container to manage objects is to find where the beans are. Resouce is used to encapsulate I/O resources in Spring regardless of their form (Class Path, FileSystem, URL, Path).
ApplicationContext realize FileSystemXmlApplicationContext commonly used as an example to illustrate this process, refresh methods don’t remember the last time said, this is the entrance to start the IoC container.
We also know that every Resource of a BeanDefinition needs a Reader to read it, and this is no exception, But in FileSystemXmlApplicationContext but can’t see any information relating to the Reader.
These are encapsulated in its original parent AbstractRefreshableApplicationContext, still want to put a piece of code.
protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; }}Copy the code
I don’t see any Resource references in the container restart method, so I’m going to have to say a little bit more here, that our BeanDefinition load is going to locate the Resource, which is a little bit more advanced, My understanding is to get a Resource object.
Let’s go ahead and see what loadBeanDefinitions is all about. Just click through and you’ll find these two key lines of code.
AbstractBeanDefinitionReaderResource resource = resourceLoader.getResource(location);
int loadCount = loadBeanDefinitions(resource);
Copy the code
LoadBeanDefinitions is a loadBeanDefinitions method that implicitly addresses Resource definitions.
So let’s just look at how getResource gets.
public Resource getResource(String location) { Assert.notNull(location, "Location must not be null"); if (location.startsWith("/")) { return getResourceByPath(location); } else if (location.startsWith(CLASSPATH_URL_PREFIX)) { return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader()); } else { try { // Try to parse the location as a URL... URL url = new URL(location); return new UrlResource(url); } catch (MalformedURLException ex) { // No URL -> resolve as resource path. return getResourceByPath(location); }}}Copy the code
We can see that this method handles not only Class Path, urls, but also Path, but this getResourceByPath is implemented by a subclass that handles Path, FileSystemXmlApplicationContext implements this method.
So this getResourceByPath is designed with a template mode, and the method is protected, and it’s implemented itself, but it’s implemented differently in subclasses, For example in FileSystemXmlApplicationContext implementation is as follows
@Override protected Resource getResourceByPath(String path) { if (path ! = null && path.startsWith("/")) { path = path.substring(1); } return new FileSystemResource(path); }Copy the code
So, we’re done with the getResource process, which is the location of the Resource, and really, this word is confusing me for a long time, but it’s nice to just say get the Resource object.
In Spring, I/O operations are defined by Resource. We get Resource as Input stream, and then we process the Input stream… Encapsulated as BeanDefinition, the abstract form of the POJO in the container. Perfect!
Loading and parsing of BeanDefinition
Because it involves too much code, AND I do not want to post code, I strongly recommend you to open the IDE to see the source code, of course, this takes time, in the case of the implementation of a lot of classes, we can first locate a few key classes and implementation.
Let’s talk about what Spring is doing in this step. Now that we’ve got the Resource object, we’ve got the Input stream, and what we’re doing is we’re going to interpret the information in the Input first through an XML parser, Which is a Document object.
Then, the DocumentReader is used to read information in the DOM. These information is encapsulated in BeanDefinitionHolder, which contains BeanDefinition information, bean name, alias, etc.
By DocumentReader load information, done by BeanDefinitionParserDelegate information parsing of load. Parsing different elements, different nodes under elements, is very complicated.
The net effect is that we encapsulate the information in XML in BeanDefinition, but that’s not registered yet. The Bean parsed into the BeanDefinition contains the class information of the XML configuration and is not instantiated.
There are two details here. If you have multiple properties with the same name in the same bean, only the first property node will be parsed. In the same container, if a Bean with the same name is resolved, the second one is in effect.
BeanDefinition injection
The injection of BeanDefinition and I just want to represent it in two lines of code
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64); beanDefinitionMap.put(beanName, beanDefinition);Copy the code
At this point, our BeanDefinition information is in the Map, so we have initialized IoC, but our Bean is still not instantiated, and no dependencies are injected.
Next time on Bean instantiation and injection dependencies…