preface
Previously, we combed through the whole process of Spring container initialization. Today, we will talk about one of the key points of the initialization process, the parsing of Spring configuration and the loading of BeanDefinition.
Although Spring configuration comes in many forms, it is no longer limited to XML files. However, this article uses the spring-Demo project from the previous article as an example to analyze how the configuration file spring-beans.xml for XML configuration is parsed. Once you’ve mastered the XML configuration form, you can look at other ways to do it by analogy.
The original demo expansion
There was a little bit of content in the demo, so let’s enrich it and then we’ll analyze it. Project address: Spring-XML-Demo-enhanced
Project structure
coding
Component, Component empty class
package cn.dingyufan.learnspring.springxmldemoenhanced.component;
import org.springframework.stereotype.Component;
@Component
public class OneComponent {}Copy the code
package cn.dingyufan.learnspring.springxmldemoenhanced.component;
import org.springframework.stereotype.Component;
@Component
public class TwoComponent {}Copy the code
HelloController adds oneComponent injection
package cn.dingyufan.learnspring.springxmldemoenhanced.controller;
import cn.dingyufan.learnspring.springxmldemoenhanced.component.OneComponent;
import cn.dingyufan.learnspring.springxmldemoenhanced.service.HelloService;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Autowired
private HelloService helloService;
@Autowired
private OneComponent oneComponent;
// The property is automatically printed after injection for easy validation
@PostConstruct
private void init(a) {
System.out.println("HelloController.init(),helloService=>" + helloService);
System.out.println("HelloController.init(),oneComponent=>" + oneComponent);
}
@GetMapping("/hello")
public ResponseEntity<String> hello(HttpServletRequest request) {
return ResponseEntity.ok("Hello Spring!");
}
@GetMapping("/check")
public ResponseEntity<String> check(HttpServletRequest request) {
return ResponseEntity.ok(String.valueOf(helloService.hashCode()));
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("HelloController injects applicationContext =>" + applicationContext.getDisplayName());
this.applicationContext = applicationContext; }}Copy the code
No change HelloService
package cn.dingyufan.learnspring.springxmldemoenhanced.service;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class HelloService implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("HelloService injections applicationContext =>" + applicationContext.getDisplayName());
this.applicationContext = applicationContext; }}Copy the code
WorldService injects multiple contents, an object, a number, and an array. It’s all configured through XML configuration and then injected by setter methods. The init() method is in the XML configuration of the init-method item, which is called in the order after the bean property is injected, so we use this method to check if the content is injected.
package cn.dingyufan.learnspring.springxmldemoenhanced.service;
import java.util.List;
public class WorldService {
private HelloService helloService;
private Integer year;
private List<String> ultraman;
// The
init-method attribute is configured in XML
private void init(a) {
System.out.println("WorldService.init(),helloService=>" + helloService);
System.out.println("WorldService.init(),year=>" + year);
System.out.println("WorldService.init(),ultraman=>" + ultraman);
}
public void setHelloService(HelloService helloService) {
this.helloService = helloService;
}
public void setUltraman(List<String> ultraman) {
this.ultraman = ultraman;
}
public void setYear(Integer year) {
this.year = year; }}Copy the code
configuration
For configuration, some common configuration tags are used in Demo.
First you can see a new spring-component.xml.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<! -- Scan and register components under base-package -->
<context:component-scan base-package="cn.dingyufan.learnspring.springxmldemoenhanced.component"/>
</beans>
Copy the code
The spring-beans. XML file adds the worldService definition and configates attributes for worldService. Added the <import> tag to import the contents of spring-component. XML into spring-beans.xml. The <import> tag makes it easier to split the managed beans and avoid a configuration file that is too large.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="helloService" class="cn.dingyufan.learnspring.springxmldemoenhanced.service.HelloService"/>
<bean id="worldService" class="cn.dingyufan.learnspring.springxmldemoenhanced.service.WorldService" init-method="init">
<property name="helloService" ref="helloService"/>
<property name="year" value="2021"/>
<property name="ultraman">
<list>
<value>Robot --</value>
<value>The severn</value>
<value>ace</value>
</list>
</property>
</bean>
<import resource="spring-component.xml"/>
</beans>
Copy the code
The spring-mvC.xml, web. XML, and pom.xml are unchanged and will not be described here, if necessary
run
As you can see from the console print, the objects, numbers, and arrays in HelloService are all successfully injected; The new oneComponent added to HelloController has also been successfully injected. It means our configuration has taken effect.
The source code parsing
From the above, configuration files are loaded during the beanFactory refresh process. We’ll still use XmlWebApplicationContext as an example, starting with the obtainFreshBeanFactory() method.
AbstractApplicationContext
The XmlWebApplicationContext obtainFreshBeanFactory () method is its parent class AbstractApplicationContext implementation
// AbstractApplicationContext.java
protected ConfigurableListableBeanFactory obtainFreshBeanFactory(a) {
/ / short method
refreshBeanFactory();
return getBeanFactory();
}
Copy the code
AbstractRefreshableApplicationContext
The XmlWebApplicationContext refreshBeanFactory () method is the parent class AbstractRefreshableApplicationContext implementation.
// AbstractRefreshableApplicationContext.java
@Override
protected final void refreshBeanFactory(a) throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
// Empty method to parse configuration load BeanDefinition
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for "+ getDisplayName(), ex); }}Copy the code
XmlWebApplicationContext
At this point, the loadBeanDefinitions(beanFactory) method is finally implemented by XmlWebApplicationContext itself.
// XmlWebApplicationContext.java
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create an XmlBeanDefinitionReader for BeanFactory
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Add configuration for XmlBeanDefinitionReader
beanDefinitionReader.setEnvironment(getEnvironment());
// Set XmlWebApplicationContext itself to ResourceLoader
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Empty method to add the desired configuration to the subclass. Template method pattern again.
initBeanDefinitionReader(beanDefinitionReader);
/ / load BeanDefinition
loadBeanDefinitions(beanDefinitionReader);
}
Copy the code
As you can see, XmlBeanDefinitionReader is prepared for parsing configurations, leaving room for custom configurations for subclasses, and then actually taking a different loadBeanDefinitions(Reader) method in another.
// XmlWebApplicationContext.java
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
String[] configLocations = getConfigLocations();
if(configLocations ! =null) {
for(String configLocation : configLocations) { reader.loadBeanDefinitions(configLocation); }}}Copy the code
As you can see from the code, the loadBeanDefinitions(Reader) method simply iterates through our XML configuration file path and then hands it over to XmlBeanDefinitionReader.
By the way, do you remember where this configLocations came from? It is context-param that we configure in web.xml and then get from servletContext and assign to applicationContext in ContextLoader.
AbstractBeanDefinitionReader
So XmlBeanDefinitionReader once we get the configuration file path, what does it do
- Get ResourceLoader
- Load the configuration file as Resource using ResourceLoader
- Iterate over the loaded Resource and call the subclass method to load the BeanDefinition
/ / AbstractBeanDefinitionReader. Java. Is XmlBeanDefinitionReader parent class
@Override
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return loadBeanDefinitions(location, null);
}
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
// This ResourceLoader is set earlier in the loadBeanDefinitions(beanFactory) method of the XmlWebApplicationContext class
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException("Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
}
XmlWebApplicationContext implements the ResourcePatternResolver interface
if (resourceLoader instanceof ResourcePatternResolver) {
try {
// Load the configuration file as Resource using ResourceLoader
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
int count = loadBeanDefinitions(resources);
if(actualResources ! =null) {
Collections.addAll(actualResources, resources);
}
if (logger.isTraceEnabled()) {
logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
}
return count;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", ex); }}else {
Resource resource = resourceLoader.getResource(location);
int count = loadBeanDefinitions(resource);
if(actualResources ! =null) {
actualResources.add(resource);
}
if (logger.isTraceEnabled()) {
logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
}
returncount; }}@Override
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int count = 0;
for (Resource resource : resources) {
// loadBeanDefinitions(Resource) is a subclass implementation
// This is the loadBeanDefinitions(Resource) method in XmlWebApplicationContext
count += loadBeanDefinitions(resource);
}
return count;
}
Copy the code
The first thing you can see is that it gets a ResourceLoader using the getResourceLoader() method, This ResourceLoader is the loadBeanDefinitions(beanFactory) method of the XmlWebApplicationContext class. We’re going to set it, and we’re going to set it to the XmlWebApplicationContext object itself. You can scroll up a little bit.
Then determine if it is the ResourcePatternResolver implementation class. XmlWebApplicationContext implements ApplicationContext, and the ApplicationContext interface inherits directly from the ResourcePatternResolver interface.
public interface ApplicationContext extends EnvironmentCapable.ListableBeanFactory.HierarchicalBeanFactory.MessageSource.ApplicationEventPublisher.ResourcePatternResolver {
@Nullable
String getId(a);
String getApplicationName(a);
String getDisplayName(a);
long getStartupDate(a);
@Nullable
ApplicationContext getParent(a);
AutowireCapableBeanFactory getAutowireCapableBeanFactory(a) throws IllegalStateException;
}
Copy the code
If we search ResourcePatternResolver’s implementation class, we can also clearly see the XmlWebApplicationContext.
Then load the configuration file as Resource. The load is dependent on the XmlWebApplicationContext parent AbstractApplicationContext ResourcePatternResolver types ResourcePatternResolver member variables. AbstractApplicationContext constructor, will create a variable instance, is a PathMatchingResourcePatternResolver. I’m not going to talk about the process, but let’s figure out which class does this.
// AbstractApplicationContext.java
public AbstractApplicationContext(a) {
this.resourcePatternResolver = getResourcePatternResolver();
}
protected ResourcePatternResolver getResourcePatternResolver(a) {
return new PathMatchingResourcePatternResolver(this);
}
Copy the code
XmlBeanDefinitionReader
The last AbstractBeanDefinitionReader call subclasses XmlBeanDefinitionReader method resolving the Resource. Going back to the XmlWebApplicationContext class, it wraps Resource as EncodedResource; Then read the file with IO stream, convert the XML file into the corresponding Document object, convenient program processing. Then instantiates a BeanDefinitionDocumentReader to read the Document object.
// XmlBeanDefinitionReader.java
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Loading XML bean definitions from " + encodedResource);
}
// Currently loaded Resource
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if(! currentResources.add(encodedResource)) {throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
InputSource inputSource = new InputSource(inputStream);
if(encodedResource.getEncoding() ! =null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
// inputStream reads Resource and continues
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove(); }}}protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
try {
// Parse the XML to form the corresponding Document object
Document doc = doLoadDocument(inputSource, resource);
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); }}public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
Copy the code
DefaultBeanDefinitionDocumentReader
Read the Document object the default is to use DefaultBeanDefinitionDocumentReader, in method and to create a BeanDefinitionParserDelegate proxy class. This method involves the processing of namespace and profile, so I will not go into details at present. There’s nothing to discuss about the two empty methods; Focus on parseBeanDefinitions(root, this.delegate).
// DefaultBeanDefinitionDocumentReader.java
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
doRegisterBeanDefinitions(doc.getDocumentElement());
}
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
// Check whether a profile is configured.
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
// We cannot use Profiles.of(...) since profile expressions are not supported
// in XML config. See SPR-12458 for details.
if(! getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {if (logger.isDebugEnabled()) {
logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
Copy the code
In this method, there are two cases, one is the default namespace, the other is actually a custom namespace (custom tag). The application of custom tags is also very widespread in Spring applications. For example, well-known frameworks such as SpringMVC and Dubbo all use custom tags. We will only look at the default namespace handling here, and the other one will be covered separately.
// DefaultBeanDefinitionDocumentReader.java
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else{ delegate.parseCustomElement(ele); }}}}else{ delegate.parseCustomElement(root); }}Copy the code
For nodes with a default namespace, the final method is parseDefaultElement(ele, delegate). The four IFs in this method parse different tags. Tag parsing is much the same, let’s take
parsing as an example.
// DefaultBeanDefinitionDocumentReader.java
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
// <import>
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
// <alias>
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
// <bean>
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
// <beans>
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recursedoRegisterBeanDefinitions(ele); }}Copy the code
Going into the processBeanDefinition(ele, delegate) method we can see that the following method does four things
- Resolve the node to BeanDefinitionHolder with the resolution Delegate proxy object
- If a Decorator is defined, the BeanDefinition is decorated
- Register the final BeanDefinition
- Send the bean registration event
In fact, the first step is the most important, and we will see how the proxy object that is responsible for parsing is handled in a moment. Use a Decorator. What does this do? A Decorator is registered in the NamespaceHandler to handle the node’s namespaceUri. More on that later.
// DefaultBeanDefinitionDocumentReader.java
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// Parse the node, creating BeanDefinitionHolder
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if(bdHolder ! =null) {
// If a decorator is defined, the BeanDefinition is decorated.
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final BeanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex);
}
// Send the bean registration event
getReaderContext().fireComponentRegistered(newBeanComponentDefinition(bdHolder)); }}Copy the code
BeanDefinitionParserDelegate
Let’s focus on BeanDefinitionHolder. The main logic for delegate parsing is as follows
- Read node id, name
- Take beanName and check if it is unique
- To parse AbstractBeanDefinition
- Create an AbstractBeanDefinition based on the className, parent type, and ClassLoader
- Read various properties and populate them with AbstractBeanDefinition
- Try beanName again
- Assemble BeanDefinitionHolder
// BeanDefinitionParserDelegate.java
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return parseBeanDefinitionElement(ele, null);
}
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
// Read node id, name
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
List<String> aliases = new ArrayList<>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
// beanName defaults to id. If id is not set to name, select the first name as id
String beanName = id;
if(! StringUtils.hasText(beanName) && ! aliases.isEmpty()) { beanName = aliases.remove(0);
if (logger.isTraceEnabled()) {
logger.trace("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases"); }}if (containingBean == null) {
// Check if beanName is repeated
checkNameUniqueness(beanName, aliases, ele);
}
// Parse the node to AbstractBeanDefinition
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if(beanDefinition ! =null) {
if(! StringUtils.hasText(beanName)) {If there is no beanName, generate a beanName
try {
if(containingBean ! =null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);
String beanClassName = beanDefinition.getBeanClassName();
if(beanClassName ! =null
&& beanName.startsWith(beanClassName)
&& beanName.length() > beanClassName.length()
&&!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) { aliases.add(beanClassName); }}if (logger.isTraceEnabled()) {
logger.trace("Neither XML 'id' nor 'name' specified - " + "using generated bean name [" + beanName + "]"); }}catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
// AbstractBeanDefinitionHolder, beanName, aliases assemble BeanDefinitionHolder
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
@Nullable
public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
// Read the class attribute in node
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
// Read the parent property in node
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
try {
// Create an AbstractBeanDefinition based on className, parent type, and ClassLoader
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
// Read various attributes and populate them with AbstractBeanDefinition. Such as:
// Singleton, scope, abstract, lazy-init, autowire, Depends -on, autowire-candidate,
// primary, init-method, destroy-method, factory-method, factory-bean
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
// Resolve the descriptionb tag
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
// Parse meta tags
parseMetaElements(ele, bd);
// parse the lookup-method tag
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
// Resolve the event-method tag
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
// Parse the constructor-arg tag
parseConstructorArgElements(ele, bd);
// Parse the property tag
parsePropertyElements(ele, bd);
// Resolve the Qualifier tag
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
}
catch (ClassNotFoundException ex) {
error("Bean class [" + className + "] not found", ele, ex);
}
catch (NoClassDefFoundError err) {
error("Class that bean class [" + className + "] depends on not found", ele, err);
}
catch (Throwable ex) {
error("Unexpected failure during bean definition parsing", ele, ex);
}
finally {
this.parseState.pop();
}
return null;
}
Copy the code
conclusion
It’s a long paragraph, maybe it’s a little bit clearer to have a picture of the process.