The following is the initialization loading of IOC container based on Xml. Please refer to the previous article for the positioning of the container Initialization of IOC container based on Xml (I) positioning
3. Start
The spring IOC container loads Bean configuration resources from the refresh () function. Refresh () is a template method that specifies the startup process of the IOC container, and some logic needs to be implemented by its subclasses. It loads Bean configuration resources. ClassPathXmlApplicationContext starts the loading process of Bean definitions by calling the refresh() function of its parent class AbstractApplicationContext. Now let's take a detailed look at the logic processing in refresh():
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext { @Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 1. Call the method that the container is ready to refresh, obtain the current time of the container, and set the synchronization ID at the same time prepareRefresh(); // Tell the subclass to start the refreshBeanFactory() method and load the Bean definition resource file from //The subclass's refreshBeanFactory() method starts ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); //3. Configure container features for BeanFactory, such as class loader, event handler, and so on prepareBeanFactory(beanFactory); try { //4. Specify a special BeanPost event handler for some subclasses of duration postProcessBeanFactory(beanFactory); //5. All postbean registrations of factorybeanprocessor invokeBeanFactoryPostProcessors(beanFactory); //6. Register the BeanPost time processor for BeanFactory. //BeanPostProcessor is a Bean post processor, which is used to listen for container trigger events registerBeanPostProcessors(beanFactory); //7. Initializing the information source is related to internationalization initMessageSource(); //8. Initialize container event propagator initApplicationEventMulticaster(); //9. Call some special Bean initialization methods of subclasses onRefresh(); //10. Register event listeners for event propagators registerListeners(); //11. Initialize all remaining singleton beans finishBeanFactoryInitialization(beanFactory); //12. Initialize the container's lifecycle event handler and publish the container's lifecycle events finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } //13. Destroy the created Bean destroyBeans(); //14. Cancel the refresh operation and reset the synchronization ID of the container cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... //Reset public cache resetCommonCaches(); } } } }
The refresh() method mainly provides conditions for the life cycle management of IOC container beans. The Spring IOC container loads Bean configuration information from the refreshBeanFactory() method of its subclass container, so ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); The code after this sentence is the information source and life cycle events of the registration container. The loading we mentioned earlier starts from this code.
The main function of refresh() method is to destroy and close the existing IOC container if it already exists before creating the IOC container, so as to ensure that the newly established IOC container is used after refresh. It is similar to restarting the IOC container, initializing the container in the newly established container and loading the Bean configuration resources.
4. Create container
obtainFreshBeanFactory() method calls the refreshBeanFactory() method of the subclass container to start the process of loading Bean configuration information into the container. The code is as follows:
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext { //The method is only defined here, not implemented protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException; protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { //The delegation design pattern is used here. The parent class defines the abstract refreshBeanFactory() method, which specifically calls the refreshBeanFactory() method of the subclass container refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; } }
The AbstractApplicationContext class only abstractly defines the refreshBeanFactory() method. What the container really calls is the refreshBeanFactory() method implemented by its subclass AbstractRefreshableApplicationContext. The source code of the method is as follows:
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext { @Override protected final void refreshBeanFactory() throws BeansException { //If there is already a container, destroy the bean s in the container and close the container if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { //Create IOC container DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); //Customize IOC containers, such as setting startup parameters, opening automatic assembly of annotations, etc customizeBeanFactory(beanFactory); //Calling the method defined by the load Bean mainly uses a delegation mode. In the current class, only the abstract loadBeanDefinitions method is defined, and the specific implementation calls the subclass container loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } } }
In this method, first judge whether the beanFactory exists. If so, first destroy the beans and close the beanFactory, then create the DefaultListableBeanFactory, and call loadbean definitions (beanFactory) to load the bean definition.
5. Load configuration path
AbstractRefreshableApplicationContext class only defines the abstract loadBeanDefinitions(beanFactory) method, which actually calls AbstractXmlApplicationContext
loadBeanDefinitions(beanFactory) method. The source code of this method is as follows:
//Notice that the AbstractRefreshableApplicationContext class is inherited here public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext { //Load Bean definition method to implement parent class abstraction @Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { //Create an XmlBeanDefinitionReader, that is, create a Bean reader and set it to the container through a callback. The container uses the reader to read the Bean definition resources XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); //Set the Spring resource loader for the Bean reader, AbstractXmlApplicationContext //The ancestor parent class AbstractApplicationContext inherits DefaultResourceLoader, so the container itself is also a resource loader beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); //Set up SAX xml parser for Bean reader beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); //When the Bean reader reads the Xml resource file defined by the Bean, enable the Xml verification mechanism initBeanDefinitionReader(beanDefinitionReader); //How to load the Bean reader loadBeanDefinitions(beanDefinitionReader); } //The Xml Bean reader loads the Bean definition resource protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { //Gets the location of the Bean definition resource Resource[] configResources = getConfigResources(); if (configResources != null) { //The Xml Bean reader calls its parent class AbstractBeanDefinitionReader to read the location //Bean definition resource for reader.loadBeanDefinitions(configResources); } //If the Bean definition resource obtained in the subclass is empty, //Gets the resource set by the setConfigLocations method in the FileSystemXmlApplicationContext constructor //Is the implementation of the Bean resource definition here! String[] configLocations = getConfigLocations(); if (configLocations != null) { //The Xml Bean reader calls its parent class AbstractBeanDefinitionReader to read the located Bean definition resource reader.loadBeanDefinitions(configLocations); } } //Here, a delegate mode is used to call the subclass's method to obtain the Bean definition resource location //This method is implemented in ClassPathXmlApplicationContext. For us //For example, the FileSystemXmlApplicationContext of the source code does not use this method (null is returned) @Nullable protected Resource[] getConfigResources() { return null; } }
Take XmlBeanDefinitionReader, one of the policies of XmlBean reader, as an example. XmlBeanDefinitionReader calls the reader of its parent class AbstractBeanDefinitionReader The loadbeandefinitions() method reads the Bean configuration resources.
Since we use ClassPathXmlApplicationContext as an example for analysis, the return value of getConfigResources is null, so the program executes reader Loadbean definitions (configlocations) branch.
6. Allocation path processing strategy
The loading process is defined in the abstract parent class AbstractBeanDefinitionReader of XmlBeanDefinitionReader.
The source code of loadBeanDefinitions() method of AbstractBeanDefinitionReader is as follows:
public abstract class AbstractBeanDefinitionReader implements EnvironmentCapable, BeanDefinitionReader { //Overload the method and call the following loadbean definitions (string, set < resource >); method //Execution sequence 2 @Override public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException { return loadBeanDefinitions(location, null); } //Execution sequence 3 public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException { //Gets the resource loader set during IoC container initialization ResourceLoader resourceLoader = getResourceLoader(); if (resourceLoader == null) { throw new BeanDefinitionStoreException( "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available"); } if (resourceLoader instanceof ResourcePatternResolver) { // Resource pattern matching available. try { //Resolve the Bean definition resource file at the specified location to the resource encapsulated by the Spring IOC container //Load Bean definition resource files at multiple specified locations Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); //Delegate to call the method of its subclass XmlBeanDefinitionReader to realize the loading function int loadCount = loadBeanDefinitions(resources); if (actualResources != null) { for (Resource resource : resources) { actualResources.add(resource); } } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]"); } return loadCount; } catch (IOException ex) { throw new BeanDefinitionStoreException( "Could not resolve bean definition resource pattern [" + location + "]", ex); } } else { // Can only load single resources by absolute URL. //Resolve the Bean definition resource file at the specified location to the resource encapsulated by the Spring IOC container //Load the Bean definition resource file of a single specified location Resource resource = resourceLoader.getResource(location); //Delegate to call the method of its subclass XmlBeanDefinitionReader to realize the loading function int loadCount = loadBeanDefinitions(resource); if (actualResources != null) { actualResources.add(resource); } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]"); } return loadCount; } } //Overload method, call loadbean definitions (string); //Reader in AbstractXmlApplicationContextd class in point 5 loadBeanDefinitions(configLocations); That's it //Execution sequence 1 @Override public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException { Assert.notNull(locations, "Location array must not be null"); int counter = 0; for (String location : locations) { counter += loadBeanDefinitions(location); } return counter; } }
The loadBeanDefinitions(DefaultListableBeanFactory beanFactory) method of creating the container AbstractRefreshableApplicationContext in step 4 actually calls the loadBeanDefinitions() method of AbstractBeanDefinitionReader.
From the source code analysis of loadBeanDefinitions() method of AbstractBeanDefinitionReader, we can see that this method does two things:
- First, call the resource loader method resourceloader Getresource (location) to get the resource to be loaded.
- Secondly, the real loading function is the loadBeanDefinitions() method of its subclass XmlBeanDefinitionReader..
In the loadBeanDefinitions() method of AbstractBeanDefinitionReader, the getResources() method of AbstractApplicationContext is invoked (because ResourceLoader is implemented by AbstractApplicationContext). After entering it, it is found that the getResources() method is actually defined in ResourcePatternResolver. It is necessary to take a look at the complete class diagram of resourcepatternresolver:
From the above, we can see the inheritance relationship between ResourceLoader and ApplicationContext. We can see that calling the getResources() method of AbstractApplicationContext actually calls the getSource() method in DefaultResourceLoader to locate the Resource, because ClassPathXmlApplicationContext itself is the implementation class of DefaultResourceLoader, So now we return to ClassPathXmlApplicationContext.