In this paper , First of all Spring Load and create bean The flow of the instance follows the source code , In the following article, we will introduce the other methods of the involved classes .
// This step is to load the specified configuration file Resource resource = new ClassPathResource("bean.xml");
//DefaultListableBeanFactory yes BeanFactory The most commonly used subclass of , Instantiate it as us IOC Container for
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// This class is used to parse configuration files , Configure the bean Load into container XmlBeanDefinitionReader reader = new
XmlBeanDefinitionReader(beanFactory); // load bean
reader.loadBeanDefinitions(resource); // This step takes the specified bean, This step is also involved bean Instantiation of
Person person = (Person) beanFactory.getBean("person");
below , We analyze each of the above steps :
Resource resource = new ClassPathResource("bean.xml");
This step is to put the path of our configuration file , Name and other attributes are put into a class , So that we can easily get all kinds of information about it .
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
Instantiated a factory class , As IOC container , Other ways about it , It will be introduced in the following articles
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
Instantiated a xml reader , This class will add all the bean Load into beanFactory in .
reader.loadBeanDefinitions(resource);
The reader begins to load bean, Start here , We follow the source code to explore how it is implemented :
public int loadBeanDefinitions(Resource resource) throws
BeanDefinitionStoreException { return loadBeanDefinitions(new
EncodedResource(resource)); }

I went in and found out , It also calls its own methods , It just sent us in resource Packed , Become EncodedResource, It's just a record resource itself , And its character set and encoding information .
continue :
public int loadBeanDefinitions(EncodedResource encodedResource) throws
BeanDefinitionStoreException { // Assert what we passed in encodedResource It's not empty
Assert.notNull(encodedResource, "EncodedResource must not be null"); // Print log if
(logger.isInfoEnabled()) { logger.info("Loading XML bean definitions from " +
encodedResource.getResource()); } // This is a set Set<EncodedResource>
currentResources = this.resourcesCurrentlyBeingLoaded.get();
//Spring It must have been empty at the start , We're going to create one set, And put it in the current thread if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources); } if
(!currentResources.add(encodedResource)) { throw new
BeanDefinitionStoreException( "Detected cyclic loading of " + encodedResource +
" - check your import definitions!"); } try { // Get the input stream of the configuration file InputStream
inputStream = encodedResource.getResource().getInputStream(); try { // Encapsulating the input stream
InputSource inputSource = new InputSource(inputStream); if
(encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding()); } // Start here , It's really going on bean Loading of
return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); }
finally { inputStream.close(); } } catch (IOException ex) { throw new
BeanDefinitionStoreException( "IOException parsing XML document from " +
encodedResource.getResource(), ex); } finally {
currentResources.remove(encodedResource); if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove(); } } }

We found that , The logic in this method is also very simple , It is to get the configuration file that we are loading from the current thread set aggregate , If not, create , Then get the input stream of the configuration file and wrap it as inputSource and resource Pass them together to the next method .
protected int doLoadBeanDefinitions(InputSource inputSource, Resource
resource) throws BeanDefinitionStoreException { ... // Get the configuration file document object
Document doc = doLoadDocument(inputSource, resource); // register bean return
registerBeanDefinitions(doc, resource); ... }

One of these methods does two things , But neither is easy , Every logic is enough for us to study for a long time ,, First, we get the configuration file document object , With it , We can analyze its nodes , after , It's about putting bean Register with beanFactory Yes .
The first step is right xml Object creation , Let's focus on the second step :
public int registerBeanDefinitions(Document doc, Resource resource) throws
BeanDefinitionStoreException { // Create a load bean Parser for BeanDefinitionDocumentReader
documentReader = createBeanDefinitionDocumentReader(); // Get the previously registered bean Number of
int countBefore = getRegistry().getBeanDefinitionCount(); // Start registration bean
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
// Return to this registration bean Number of return getRegistry().getBeanDefinitionCount() - countBefore; }
In fact, we can also find out here ,Spring Many complex logic is divided into small parts , It's very organized , It's also easy for us to read . We continue to follow up bean Registration of :
public void registerBeanDefinitions(Document doc, XmlReaderContext
readerContext) { this.readerContext = readerContext; logger.debug("Loading bean
definitions"); // get document Root node of Element root = doc.getDocumentElement();
// It's only here that I start to register doRegisterBeanDefinitions(root); }
This method does nothing , We found that Spring It's often true that logic is implemented in do How to start :
protected void doRegisterBeanDefinitions(Element root) {
// A delegation is generated here , Because there may be nested configuration files in the configuration file , So there are recursive calls BeanDefinitionParserDelegate parent =
this.delegate; this.delegate = createDelegate(getReaderContext(), root,
parent); ... // Preprocessing preProcessXml(root); // analysis bean parseBeanDefinitions(root,
this.delegate); // Post processing postProcessXml(root); this.delegate = parent; }

In this method, a delegate is proposed , One delegate It represents one beans, yes Spring Root label in configuration file , In the following analysis , It's all entrusted to him ,createDelegate() In this method, it is right beans Analysis of this tag . We found that there are two methods in this method called :preProcessXml and postProcessXml, Click to find out that they are empty , In fact, it's up to the user to customize to achieve some special needs . Follow up code :
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate
delegate) { // Is the current configuration file to be resolved the default namespace if (delegate.isDefaultNamespace(root)) {
// Get all child nodes , A child node is a bean NodeList nl = root.getChildNodes(); for (int i = 0;
i < nl.getLength(); i++) { Node node = nl.item(i); // Is the current child node a element if
(node instanceof Element) { Element ele = (Element) node; // Is it the default namespace if
(delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); } else
{ // individualization delegate.parseCustomElement(ele); } } } } else { // individualization
delegate.parseCustomElement(root); } }
This method is mainly used to determine whether the node is the default namespace , Analyze them separately , ad locum , Let's just look at the resolution of the default namespace :
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate
delegate) { // Yes import Label parsing if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele); } // Yes alias Label parsing else if
(delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele);
} // Yes bean Label parsing else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele,
NESTED_BEANS_ELEMENT)) { // recurse doRegisterBeanDefinitions(ele); }
This method provides different parsing methods for different tags , Let's do it first bean The analysis of tags is studied , Other tags will be studied in the future
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate
delegate) { // Resolve current node BeanDefinitionHolder bdHolder =
delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) {
// After parsing the node, we need to fill in the attributes bdHolder =
delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // register bean
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,
getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex); } // Generate a time
getReaderContext().fireComponentRegistered(new
BeanComponentDefinition(bdHolder)); } }
Clear the clouds and see the sun , It's finally starting to parse :
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable
BeanDefinition containingBean) { // The first is to get the current bean Of id and name attribute String id =
ele.getAttribute(ID_ATTRIBUTE); String nameAttr =
ele.getAttribute(NAME_ATTRIBUTE); // Get alias List<String> aliases = new
ArrayList<>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr =
StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr)); } take bean The name of is set to id String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { beanName =
aliases.remove(0); if (logger.isDebugEnabled()) { logger.debug("No XML 'id'
specified - using '" + beanName + "' as bean name and " + aliases + " as
aliases"); } } if (containingBean == null) { checkNameUniqueness(beanName,
aliases, ele); } // analysis bean Other properties in AbstractBeanDefinition beanDefinition =
parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition
!= null) { // If the current bean In the definition beanName Is empty , So, for the present bean Generate a name according to the specified rules if
(!StringUtils.hasText(beanName)) { try { if (containingBean != null) { beanName
= BeanDefinitionReaderUtils.generateBeanName( beanDefinition,
this.readerContext.getRegistry(), true); } else { beanName =
this.readerContext.generateBeanName(beanDefinition); // Register an alias for
the plain bean class name, if still possible, // if the generator returned the
class name plus a suffix. // This is expected for Spring 1.2/2.0 backwards
compatibility. String beanClassName = beanDefinition.getBeanClassName(); if
(beanClassName != null && beanName.startsWith(beanClassName) &&
beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName); } } if (logger.isDebugEnabled()) {
logger.debug("Neither XML 'id' nor 'name' specified - " + "using generated bean
name [" + beanName + "]"); } } catch (Exception ex) { error(ex.getMessage(),
ele); return null; } } // Change alias to string array String[] aliasesArray =
StringUtils.toStringArray(aliases); // Return after setting parameters return new
BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null; }

This method is mainly used to bean Various attributes in the tag are analyzed , Default values are used for those not declared in the configuration file , It's not right yet bean Analysis of sub node of label and signature , Here we see a new class emerging BeanDefinitionHolder, It's actually right beanDefinition,beanName and aliasesArray Temporary encapsulation of , Wait until now bean After all parsing, the information it encapsulates will be enlarged IOC In the container .
public BeanDefinitionHolder decorateBeanDefinitionIfRequired( Element ele,
BeanDefinitionHolder definitionHolder, @Nullable BeanDefinition containingBd) {
BeanDefinitionHolder finalDefinition = definitionHolder;
// Some attributes are not directly placed in the bean Inside the label , It's about putting bean The next level of the tag , Parse these properties NamedNodeMap attributes =
ele.getAttributes(); for (int i = 0; i < attributes.getLength(); i++) { Node
node = attributes.item(i); finalDefinition = decorateIfRequired(node,
finalDefinition, containingBd); } // Decorate based on custom nested elements.
NodeList children = ele.getChildNodes(); for (int i = 0; i <
children.getLength(); i++) { Node node = children.item(i); if
(node.getNodeType() == Node.ELEMENT_NODE) { finalDefinition =
decorateIfRequired(node, finalDefinition, containingBd); } } return
finalDefinition; }

In this method, we mainly focus on bean The nodes in the tag that are not the default namespace are resolved , And set the value to bean In the definition . So far , A complete bean It's finished , Now we will finish the analysis bean Register with IOC In the container :
public static void registerBeanDefinition( BeanDefinitionHolder
definitionHolder, BeanDefinitionRegistry registry) throws
BeanDefinitionStoreException { // obtain bean The name of String beanName =
definitionHolder.getBeanName(); // according to beanName register bean
registry.registerBeanDefinition(beanName,
definitionHolder.getBeanDefinition()); // Register alias String[] aliases =
definitionHolder.getAliases(); if (aliases != null) { // Register aliases one by one for (String
alias : aliases) { registry.registerAlias(beanName, alias); } } }
Let's look at it separately , Take a look at registration first bean The process of :
public void registerBeanDefinition(String beanName, BeanDefinition
beanDefinition) throws BeanDefinitionStoreException { ... // Take a look at this bean Have you ever been registered
BeanDefinition oldBeanDefinition; oldBeanDefinition =
this.beanDefinitionMap.get(beanName); if (oldBeanDefinition != null) { if
(!isAllowBeanDefinitionOverriding()) { // this bean It's already registered , And it is not allowed to be covered , Throw an exception ... } ...
// Override registration this.beanDefinitionMap.put(beanName, beanDefinition); } else {
// There are others at this time bean Start creating , To prevent concurrency, the IOC Container locking , If there is no other bean Creating , Register directly if
(hasBeanCreationStarted()) { // Cannot modify startup-time collection elements
anymore (for stable iteration) synchronized (this.beanDefinitionMap) {
// take bean Register to container this.beanDefinitionMap.put(beanName, beanDefinition);
// Update registered bean List of names for List<String> updatedDefinitions = new
ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName); this.beanDefinitionNames =
updatedDefinitions; if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
updatedSingletons.remove(beanName); this.manualSingletonNames =
updatedSingletons; } } } else { // Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName); } this.frozenBeanDefinitionNames =
null; } if (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName); } }

This method first checks for the same beanName Be registered and dealt with accordingly , Then the beanName As key,beanDefinition As value put to IOC In the container , And update the registered bean List of names for . When there are others bean When it's being created , To prevent concurrency , Yes IOC The container is locked .
public void registerAlias(String name, String alias) { ... if
(alias.equals(name)) { this.aliasMap.remove(alias); } else { String
registeredName = this.aliasMap.get(alias); if (registeredName != null) { if
(registeredName.equals(name)) { // An existing alias - no need to re-register
return; } if (!allowAliasOverriding()) { throw new
IllegalStateException("Cannot register alias '" + alias + "' for name '" + name
+ "': It is already registered for name '" + registeredName + "'."); } }
// Check for an alias loop . If it exists , Throw an exception checkForAliasCircle(name, alias); // Add an alias to the alias list
this.aliasMap.put(alias, name); } }
okay , To this one bean The load of is complete , Let's look back :
One , Specifies the configuration file to load
Two , item base IOC container
Three , Instantiate a reader that parses configuration files , And set our instantiated IOC container
Four , Start loading bean
1, encapsulation resource, Go to the next method for processing
2, Record the currently loaded resource
3, Get the input stream of the configuration file , Start parsing
4, take xml File replacement document object , Resolve for each node
5, Create a parse document Object parser , get root node , Start parsing
6, There is a pre-processing and post-processing before and after formal parsing , User defined implementation for special requirements
7, ergodic root All child nodes of , Depending on whether the node is the default namespace , Choose different parsing methods
8, Choose different parsing methods according to different tags , In this paper, it is based on bean Tag example

9, take bean All attributes of the tag are encapsulated in the beanDefinition in , And will beanDefinition,beanName as well as alias Package to beanDefinitionHolder Further treatment should be made in
10, Parsing complete , Alias ,beanDefinition according to beanName Register with IOC In the container , Waiting for instance creation
In the next article , We will be right Spring Yes bean Instance creation process for source code interpretation .

Technology
©2019-2020 Toolsou All rights reserved,
c Language implementation 《 Student management system 》 No hole is the future of mobile phone ? There are still many problems to be solved Junior , A little sense , Just for mutual encouragement How to use Vue Used in Echarts Visual Library The 11th Blue Bridge Cup Java The second provincial competition B Group part Python- be based on OpenCV Contour fill for flooding algorithm hole filling 【C#】 The realization of student achievement information management system List Common interview questions in the collection and simple ideas China Mobile Science Popularization : Why do mobile networks call “ Cellular mobile network ”【Golang Basic series 10 】Go language On conditional sentences if