Loading BeanDefinition into Spring's IOC


This article mainly analyses the loading of BeanDefinition in spring, for which we will specially analyze it in later articles.
BeanDefinition is part of the Spring Bean module and is for spring beansUnified abstract description defines interfaces. We know that beans are defined in spring in many ways, such as XML, annotations, and custom tags. Colleague beans are also of many types, such as common factory beans, custom objects, advisors, and so on. Before analyzing and loading BeanDefinition, we first understand its definition and registration design.

Let's give a brief introduction to the class diagram above, with a detailed description of the related articles that follow.

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

  • BeanDefinitionRegistry is mainly used to register the description information of beans into containers. spring generally registers beans after they have been acquired by BeanDefinitionRegistry when in the current BeanFactory

  • BeanDefinition is the basic information used to define the name, scope, role, dependency, lazy loading of a Bean, as well as the properties associated with running and managing the Bean information for the spring container.It enables customization and unification of beans in spring, which is also a core interface layer

  • AnnotatedBeanDefinition is an interface that inherits BeanDefinition and extends it to describe the definition of annotated beans

  • AttributeAccessor is mainly used to set the interface of attributes and attribute values in Bean configuration information to implement key-value mapping relationship

  • AbstractBeanDefinition is an abstract implementation of BeanDefintion, a template whose detailed implementation is given to subclasses

2. BeanDefinition

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

The code above is the process from locating resources to loading in spring, so we can analyze it briefly:

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

The whole process is divided into three major steps, the diagram:

Our main analysis is the second step, the loading process.

3.loadBeanDefinitions

The positioning of resources has been analyzed in the previous article, but not explained. Here we are concerned about reader.loadBeanDefinitions (resources); the implementation of this sentence.
From code tracking we can see that the method #loadBeanDefinitions(...) is defined in BeanDefinitionReader, and his implementation is in the XmlBeanDefinitionReader class, with the following code:

/**
	 * Load the definition of a bean from a 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 Private Method Processing Here resource is encoded to ensure correct analysis
		return loadBeanDefinitions(new EncodedResource(resource));
	}
	/**
	 * True handling of load bean definitions
	 * 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 - > Resources that have been loaded
		Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
		//3. If the currently loaded resource is empty, create and add it
		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 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. Ways to actually execute 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();
			}
		}
	}
  • Get the loaded resource through the resourcesCurrentlyBeingLoaded.get() code, then add encodedResource to it, throw the BeanDefinitionStoreException if the resource already exists in resourcesCurrentlyBeingLoaded.

  • Why do I need to do this?The answer is "Detected cyclic loading", which prevents an EncodedResource from loading itself before it has finished loading, causing an endless loop.Therefore, when an EncodedResource is loaded, it needs to be excluded from the cache.

  • Get the encapsulated esource resource from encodedResource, get the corresponding InputStream from Resource, encapsulate InputStream as InputSource, and finally call the #doLoadBeanDefinitions(InputSource inputSource, Resource resource) method to execute the real logic of loading BeanDefinition

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {
		try {
			//1. Get an instance of Document
			Document doc = doLoadDocument(inputSource, resource);
			//2. Register the bean real column, through 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 #registerBeanDefinitions(...) method above is the specific loading process of the beanDefinition, #doLoadDocument(...) is the method for parsing a document which contains both a spring validation model and a document parsing block, which we will analyze specifically later

This article was published by AnonyStar and can be reproduced with the original source statement.
Admire the Art of Elegant Coding and believe that practice makes life better
Welcome to Weixin Public Account: Cloud Simplified Code for more quality articles
More articles focus on the author's blog: Cloud-dwelling Simplified Code

Tags: Java xml Spring Attribute encoding

Posted on Mon, 18 May 2020 09:51:49 -0700 by rilitium