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,
1190 Reverses the substring between each pair of parentheses leetcodemysql Joint index details You don't know ——HarmonyOS Create data mysql Library process Character recognition technology of vehicle license plate based on Neural Network A guess number of small games , use JavaScript realization Talking about uni-app Page value transfer problem pytorch of ResNet18( Yes cifar10 The accuracy of data classification is achieved 94%)C++ Method of detecting memory leak One is called “ Asking for the train ” A small village Finally got the train