Learn more about Java basics


The Spring source code was too big for me to read for the first time, so I decided to look at it module by module and write down articles that I thought were good during the learning process. I suggest you read the recommendation blog first, and then see what I add. Current Spring version 4.3.18

Spring reads from the definition XML file parsing

        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Copy the code

Focus on

Start the process of the whole container, are AbstractApplicationContext refresh () method of the template

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				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... resetCommonCaches(); }}}Copy the code

The focus of this tutorial is the obtainFreshBeanFactory() method.

Recommend the blog

  • Read the source code and sequence diagram to thoroughly understand the Spring container: this article is very good reading order, follow the code running order, and sequence diagram to assist learning, but only read this article, or a little confused, mainly some details are not enough, and the summary is rather rough. The following articles should be studied together.
  • Spring Ioc container Loading: This series consists of four chapters, which are clear on the details. It is divided into three modules to explain the method summary and plain language description, easier to understand. The disadvantage is that the order is not good enough, often jumping from one place to another.

conclusion

I spent time to redraw the sequence diagram, but the process was too long, and the quality of the whole process was not good. So I’m going to draw both the overall and the local sequence diagrams so you can compare them

The following is the text supplement of the whole sequence diagram:

SpringMain->ClassPathXmlApplicationContext: new ClassPathXmlApplicationContext("applicationContext.xml");
ClassPathXmlApplicationContext->AbstractRefreshableConfigApplicationContext: setConfigLocations()
AbstractRefreshableConfigApplicationContext->ClassPathXmlApplicationContext: return
ClassPathXmlApplicationContext->AbstractApplicationContext: refresh()
AbstractApplicationContext->AbstractApplicationContext: obtainFreshBeanFactory()
AbstractApplicationContext->AbstractRefreshableApplicationContext: refreshBeanFactory()
AbstractRefreshableApplicationContext->AbstractXmlApplicationContext: loadBeanDefinitions()
AbstractXmlApplicationContext->AbstractXmlApplicationContext: loadBeanDefinitions()
AbstractXmlApplicationContext->AbstractBeanDefinitionReader: reader.loadBeanDefinitions(configLocations);
AbstractBeanDefinitionReader->AbstractBeanDefinitionReader: counter += loadBeanDefinitions(location);
AbstractBeanDefinitionReader->AbstractBeanDefinitionReader: return loadBeanDefinitions(location, null);
AbstractBeanDefinitionReader->XmlBeanDefinitionReader: int loadCount = loadBeanDefinitions(resource);
XmlBeanDefinitionReader->XmlBeanDefinitionReader: doLoadBeanDefinitions()
XmlBeanDefinitionReader->XmlBeanDefinitionReader: registerBeanDefinitions()
XmlBeanDefinitionReader->DefaultBeanDefinitionDocumentReader: registerBeanDefinitions(doc, createReaderContext(resource));
DefaultBeanDefinitionDocumentReader->DefaultBeanDefinitionDocumentReader: doRegisterBeanDefinitions()
DefaultBeanDefinitionDocumentReader->DefaultBeanDefinitionDocumentReader: parseBeanDefinitions()
DefaultBeanDefinitionDocumentReader->DefaultBeanDefinitionDocumentReader: parseDefaultElement()
DefaultBeanDefinitionDocumentReader->DefaultBeanDefinitionDocumentReader: processBeanDefinition()
DefaultBeanDefinitionDocumentReader->BeanDefinitionParserDelegate: parseBeanDefinitionElement()
BeanDefinitionParserDelegate->BeanDefinitionParserDelegate: parseBeanDefinitionElement(ele, beanName, containingBean);
note right of BeanDefinitionParserDelegate: parsePropertyElements(ele, bd);
BeanDefinitionParserDelegate->DefaultBeanDefinitionDocumentReader: return new BeanDefinitionHolder
DefaultBeanDefinitionDocumentReader->BeanDefinitionParserDelegate: decorateBeanDefinitionIfRequired
DefaultBeanDefinitionDocumentReader->BeanDefinitionReaderUtils: registerBeanDefinition
BeanDefinitionReaderUtils->DefaultListableBeanFactory: registerBeanDefinition
note right of DefaultListableBeanFactory: this.beanDefinitionMap.put(beanName, beanDefinition);
note right of DefaultListableBeanFactory: this.beanDefinitionNames.add(beanName);
DefaultListableBeanFactory->DefaultBeanDefinitionDocumentReader: return 
DefaultBeanDefinitionDocumentReader->AbstractApplicationContext: obtainFreshBeanFactory() is over,return DefaultListableBeanFactory
Copy the code
  • inparsePropertyElements(ele, bd);Put the class attribute value into the bean and return the BeanDefinitionHolder.
  • inthis.beanDefinitionNames.add(beanName);andthis.beanDefinitionMap.put(beanName, beanDefinition);The beanName is placed in the queue, the BeanDefinition is placed in the map, and the registration is complete. Later instantiations take beanDefinitionMap beanDefinitionMap and instantiate it one by one

To sum up:

  1. ApplicationContext delegates parsing configuration files to BeanDefinitionReader, which reads configuration files as XML Document documents, Entrusted to BeanDefinitionDocumentReader again
  2. BeanDefinitionDocumentReader this component is based on XML element namespace and element names, have the effect of a route, the actual parsing work, is entrusted to BeanDefinitionParserDelegate to complete
  3. BeanDefinitionParserDelegate analytical work has been completed, will return BeanDefinitionHolder BeanDefinitionDocumentReader, here, Registration will be done entrusted to DefaultListableBeanFactory bean
  4. XmlBeanDefinitionReader (counting, parse the XML document), BeanDefinitionDocumentReader (depend on the XML document parsing and registration), BeanDefinitionParserDelegate analytical work (the actual). It can be seen that in the process of bean parsing, the division of labor of these three components is relatively clear, and each plays its own role

GetBean method

        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        JSONArray person = (JSONArray) context.getBean("aaa");
Copy the code

Recommend the blog

  • 【Spring source code learning 】getBean (on) : this article order is good, convenient for the first time to see the source code follow the steps, the disadvantage is to speak less, there is no summary
  • GetBean source code full interpretation: this article summarizes more, the disadvantage is that the structure order is disorderly, I will supplement its order below
  • Spring IOC container source code analysis – get singleton beans

supplement

Spring source learning 】 【 getBean (on) about a BeanDefinitionParseDelegate # parseBeanDefinitionAttributes method, the execution of the method is read from the definition of XML parsing in the above, Run to the BeanDefinitionParserDelegate # parseBeanDefinitionElement method, the diagram below

The flow chart

The sequence of this article is confusing, so I took the time to redraw the sequence diagram to make it easier to understand:

Sequence diagram text supplement:

SpringMain-> AbstractBeanFactory: getBean
AbstractBeanFactory-> AbstractBeanFactory#doGetBean: doGetBean
AbstractBeanFactory#doGetBean-> DefaultSingletonBeanRegistry: getSingleton(beanName)
AbstractBeanFactory#doGetBean-> AbstractBeanFactory#getObjectForBeanInstance: getObjectForBeanInstance
AbstractBeanFactory#doGetBean-> AbstractBeanFactory#getMergedLocalBeanDefinition: getMergedLocalBeanDefinition
AbstractBeanFactory#getMergedLocalBeanDefinition-> AbstractBeanFactory#getMergedLocalBeanDefinition: getMergedBeanDefinition
AbstractBeanFactory#doGetBean-> DefaultSingletonBeanRegistry: registerDependentBean
AbstractBeanFactory#doGetBean-> DefaultSingletonBeanRegistry: getSingleton
DefaultSingletonBeanRegistry-> DefaultSingletonBeanRegistry: beforeSingletonCreation
AbstractBeanFactory#doGetBean-> AbstractAutowireCapableBeanFactory#createBean: createBean
AbstractAutowireCapableBeanFactory#createBean-> AbstractAutowireCapableBeanFactory#doCreateBean: doCreateBean
AbstractAutowireCapableBeanFactory#doCreateBean-> AbstractAutowireCapableBeanFactory#createBeanInstance: createBeanInstance
AbstractAutowireCapableBeanFactory#createBeanInstance-> AbstractAutowireCapableBeanFactory#instantiateBean: instantiateBean
AbstractAutowireCapableBeanFactory#instantiateBean->SimpleInstantiationStrategy: instantiate
AbstractAutowireCapableBeanFactory#doCreateBean-> AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors: applyMergedBeanDefinitionPostProcessors
AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors-> AutowiredAnnotationBeanPostProcessor: postProcessMergedBeanDefinition
AutowiredAnnotationBeanPostProcessor-> AutowiredAnnotationBeanPostProcessor: findAutowiringMetadata
AutowiredAnnotationBeanPostProcessor-> AutowiredAnnotationBeanPostProcessor: buildAutowiringMetadata
AbstractAutowireCapableBeanFactory#doCreateBean-> AbstractAutowireCapableBeanFactory#populateBean: populateBean
AbstractAutowireCapableBeanFactory#populateBean-> AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues: postProcessPropertyValues
AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues-> InjectionMetadata: inject.
note right of InjectionMetadata: @Resource
AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues-> AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement: inject
note right of AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement: @Autowired&@Value
AbstractAutowireCapableBeanFactory#populateBean-> AbstractAutowireCapableBeanFactory#populateBean: applyPropertyValues
Copy the code

In AutowiredAnnotationBeanPostProcessor# buildAutowiringMetadata method, the Spring will according to different annotations, the @ the Resource or the @autowired, for example, to create different classes to return. The different classes created here will be used when InjectionMetadata #inject, and the different inject methods will be called to implement the property injection.

Circular dependencies

Recommend the blog

  • Spring dependency Injection — cyclic dependency
  • Source code analysis of the Spring IOC container – a solution to loop dependencies
  • Understand Spring loop references (loop dependencies)

conclusion

Three layers of cache

/** Cache of singleton objects: bean name --> bean instance */ private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256); /** Cache of singleton factories: bean name --> ObjectFactory */ private final Map<String, ObjectFactory<? >> singletonFactories = new HashMap<String, ObjectFactory<? > > (16); /** Cache of early singleton objects: bean name --> bean instance */ private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);Copy the code
The cache use
singletonObjects Used to hold fully initialized beans and beans taken from this cache can be used directly
earlySingletonObjects Store the original bean object (not yet populated with properties) to resolve loop dependencies
singletonFactories Store bean factory objects to resolve loop dependencies

Here are three examples. A depends on B (B does not depend on A)

Level 1 cache A depends on B && B depends on A

Level 3 cache A depends on B &&B depends on A + B depends on C &&C depends on A