In depth analysis of Spring IOC loading BeanDefinition case details

Posted by Dm7 on Tue, 19 May 2020 13:12:46 +0200

 


This paper mainly analyzes the loading of BeanDefinition in spring. We will focus on its analysis in the following articles.
BeanDefinition belongs to the spring bean module. It's for the spring bean We know that there are many ways to define beans in spring, such as XML, annotations, and custom tags. There are also many types of colleague beans, such as common factory beans, custom objects, and advisors. Before we analyze and load bean definition, we first understand its definition and registration design.

We will make a brief introduction to the above class diagram, which is detailed in the following related articles. In addition, we should pay attention to: in addition to the cases mentioned in this article. I also collated the latest 5 sets of JAVA architecture project practical tutorials and large factory interview question bank. You can enter 783802103 if you need, under the skirt file, you can't enter without foundation!

  • AliasRegistry registers the top-level interface of an alias for a Bean

  • BeanDefinitionRegistry is mainly used to register the bean description information into the container. When spring registers a bean, it usually obtains the bean and registers it in the current BeanFactory through BeanDefinitionRegistry

  • BeanDefinition is used to define the basic information such as the name, scope, role, dependency and lazy load of a Bean, as well as the attributes related to the spring container's running and managing Bean information. In spring, the customization and unification of beans are realized through it, which is also a core interface layer

  • Annotated Bean definition is an interface that inherits Bean definition and extends it to some extent. It is mainly used to describe the definition information of annotation Bean

  • AttributeAccessor is mainly used to set the interface of attribute and attribute value in Bean configuration information, and realize the key value mapping relationship

  • AbstractBeanDefinition is an abstract implementation of beandefinition. It is a template. The specific detailed implementation is handed over to the subclass

2. BeanDefinition

ClassPathResource resource = new ClassPathResource("bean.xml"); // <1>
DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); // <2>
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory); // <3>
reader.loadBeanDefinitions(resource);

The above code is the process from resource location to loading in spring. We can analyze it briefly:

  1. Locate the resource through ClassPathResource and obtain the resource
  2. Get BeanFactory, that is, context
  3. Create a specific XmlBeanDefinitionReader object through the factory, which is a resource parser and implements the BeanDefinitionReader interface
  4. Load resources

The whole process is divided into three steps

Our article mainly analyzes the second step, the loading process,

3.loadBeanDefinitions

We have analyzed the positioning of resources in the previous article, not in the elaboration, here we care about reader.loadBeanDefinitions The concrete implementation of this sentence,
Through code tracing, we can know that the method loadBeanDefinitions(...) is defined in BeanDefinitionReader, and its specific implementation is in the XmlBeanDefinitionReader class. The code is as follows:

/**
	 * Load the bean definition from the specified xml file
	 * Load bean definitions from the specified XML file.
	 * @param resource the resource descriptor for the XML file
	 * @return the number of bean definitions found
	 * @throws BeanDefinitionStoreException in case of loading or parsing errors
	 */
	@Override
	public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
		//Call the private method to process. Here, the resource is encoded to ensure the correctness of the resolution
		return loadBeanDefinitions(new EncodedResource(resource));
	}
	/**
	 * Real processing method of loading bean definition
	 * Load bean definitions from the specified XML file.
	 * @param encodedResource the resource descriptor for the XML file,
	 * allowing to specify an encoding to use for parsing the file
	 * @return the number of bean definitions found
	 * @throws BeanDefinitionStoreException in case of loading or parsing errors
	 */
	public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
		//1. Empty resource
		Assert.notNull(encodedResource, "EncodedResource must not be null");
		if (logger.isTraceEnabled()) {
			logger.trace("Loading XML bean definitions from " + encodedResource);
		}
		//2. Get the EncodedResource collection in the current thread - > loaded resources
		Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
		//3. If the currently loaded resource is empty, create and add
		if (currentResources == null) {
			currentResources = new HashSet<>(4);
			this.resourcesCurrentlyBeingLoaded.set(currentResources);
		}
		//4. Add resources to the collection throw an exception if there are loaded resources
		if (!currentResources.add(encodedResource)) {
			throw new BeanDefinitionStoreException(
					"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
		}
		//5. Get the Resource in the encodedResource, and get the intputSteram object
		try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
			InputSource inputSource = new InputSource(inputStream);
			if (encodedResource.getEncoding() != null) {
				inputSource.setEncoding(encodedResource.getEncoding());
			}
			//6. Real implementation of loading beanDefinition business logic
			return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException(
					"IOException parsing XML document from " + encodedResource.getResource(), ex);
		}
		finally {
			//7. Remove resources from loaded collections
			currentResources.remove(encodedResource);
			if (currentResources.isEmpty()) {
				this.resourcesCurrentlyBeingLoaded.remove();
			}
		}
	}
  • Through resourcesCurrentlyBeingLoaded.get() code to get the loaded resource, and then add encodedResource to it. If the resource already exists in resourcecurrentlybeingloaded, a BeanDefinitionStoreException exception will be thrown.

  • Why is this necessary? The answer is "Detected cyclic loading", to avoid an EncodedResource loading itself before it has finished loading, resulting in a dead cycle. Therefore, when an encoded resource is loaded, it needs to be removed from the cache.

  • Get the encapsulated Resource resources from encodedResource, get the corresponding InputStream from Resource, then encapsulate InputStream as InputSource, and finally call #doLoad BeanDefinition s (InputSource inputSource, Resource resource) method to implement the real logic of loading the inputSource.

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {
		try {
			//1. Get the Document instance
			Document doc = doLoadDocument(inputSource, resource);
			//2. Register the bean actual column, and use the document
			int count = registerBeanDefinitions(doc, resource);
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + count + " bean definitions from " + resource);
			}
			return count;
		}
		catch (BeanDefinitionStoreException ex) {
			throw ex;
		}
		catch (SAXParseException ex) {
			throw new XmlBeanDefinitionStoreException(resource.getDescription(),
					"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
		}
		catch (SAXException ex) {
			throw new XmlBeanDefinitionStoreException(resource.getDescription(),
					"XML document from " + resource + " is invalid", ex);
		}
		catch (ParserConfigurationException ex) {
			throw new BeanDefinitionStoreException(resource.getDescription(),
					"Parser configuration exception parsing XML from " + resource, ex);
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException(resource.getDescription(),
					"IOException parsing XML document from " + resource, ex);
		}
		catch (Throwable ex) {
			throw new BeanDefinitionStoreException(resource.getDescription(),
					"Unexpected exception parsing XML document from " + resource, ex);
		}
	}

The above ා registerBeanDefinitions(...) method is the specific loading process of beanDefinition, and ා doLoadDocument(...) is the method for parsing document, which contains two parts: spring's validation model and document parsing. We will analyze them later
Finally note: in addition to the cases mentioned in this article. I also collated the latest 5 sets of JAVA architecture project practical tutorials and large factory interview question bank. You can enter 783802103 if you need, under the skirt file, you can't enter without foundation!

The text and pictures of this article come from the Internet and my own ideas. They are only for learning and communication. They have no commercial use. The copyright belongs to the original author. If you have any questions, please contact us in time for handling

Topics: Java xml Spring Attribute