preface
The previous chapter traced the bean loading step by step from the source. Bean loading requires parsing configuration files, but there are different tags in the configuration file. Spring uses different parsing logic for different tags, including import, beans, beans, and alias
Bean label parsing
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {/ / on the interpretation of the import label the if (delegate) nodeNameEquals (ele, "import")) { this.importBeanDefinitionResource(ele); } else if (delegate. NodeNameEquals (ele, "alias")) {/ / on the interpretation of alias tag enclosing processAliasRegistration (ele); } else if (delegate. NodeNameEquals (ele, "bean")) {/ / on the interpretation of bean tag enclosing processBeanDefinition (ele, delegate); } else if (delegate. NodeNameEquals (ele, "beans")) {/ / on the interpretation of beans tag enclosing doRegisterBeanDefinitions (ele); }}Copy the code
The bean label parsing is the most complex, as long as you understand the bean label parsing, other tags will be easily solved
Protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {/ / return in the configuration file attributes BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder ! = null) {/ / no is empty, if the default label the child nodes of the custom attributes, need to custom tag parsed bdHolder = delegate. DecorateBeanDefinitionIfRequired (ele, bdHolder); After the try {/ / parsing is complete to register BeanDefinitionReaderUtils bdHolder. RegisterBeanDefinition (bdHolder, this.getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException var5) { this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5); } this.getreaderContext ().FireComponentRegistered (New BeanComponentDefinition(bdHolder)); }}Copy the code
delegate.parseBeanDefinitionElement(ele); Parsing is done in this method
@Nullable public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @nullable BeanDefinition containingBean) {String id = ele.getAttribute("id"); // Parse the name attribute String nameAttr = ele.getAttribute("name"); List<String> aliases = new ArrayList(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; "); aliases.addAll(Arrays.asList(nameArr)); } String beanName = id; if (! StringUtils.hasText(id) && ! aliases.isEmpty()) { beanName = (String)aliases.remove(0); if (this.logger.isTraceEnabled()) { this.logger.trace("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases"); } } if (containingBean == null) { this.checkNameUniqueness(beanName, aliases, ele); AbstractBeanDefinition AbstractBeanDefinition beanDefinition = GenericBeanDefinition AbstractBeanDefinition this.parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition ! = null) { if (! StringUtils.hasText(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 (this.logger.isTraceEnabled()) { this.logger.trace("Neither XML 'id' nor 'name' specified - using generated bean name [" + beanName + "]"); } } catch (Exception var9) { this.error(var9.getMessage(), ele); return null; } } String[] aliasesArray = StringUtils.toStringArray(aliases); return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } else { return null; }}Copy the code
After parsing, the information is eventually encapsulated in a BeanDefinitionHolder, which also creates an implementation of BeanDefinition, GenericBeanDefinition
Spring converts the bean configuration information in the configuration file to an internal container representation through BeanDefinitions, and registers these BeanDefinitionRegisity
public abstract class BeanDefinitionReaderUtils { public static final String GENERATED_BEAN_NAME_SEPARATOR = "#"; public BeanDefinitionReaderUtils() { } public static AbstractBeanDefinition createBeanDefinition(@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException { GenericBeanDefinition bd = new GenericBeanDefinition(); bd.setParentName(parentName); if (className ! = null) { if (classLoader ! < span style = "box-sizing: border-box; color: RGB (51, 51, 51); line-height: 22px; font-size: 13px! Important;" Not simply new an object bd.setBeanClass(classutils.forname (className, classLoader)); } else { bd.setBeanClassName(className); } } return bd; }Copy the code
All configurations in Xml can be found in the GenericBeanDefinition instance class, but GenericBeanDefinition is only a subclass implementation, and most general properties are stored in AbstractBeanDefinition
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor implements BeanDefinition, Cloneable {------- // scope @nullable private String scope; private boolean abstractFlag; @nullable private Boolean lazyInit; Private int autowireMode; private int dependencyCheck; @Nullable private String[] dependsOn; private boolean autowireCandidate; private boolean primary; -------Copy the code
That completes the bean parsing, which is the process of encapsulating the XML configuration into GenericBeanDefinition, which implements BeanDefinition, Finally, BeanDefinitionHolder has a dependency on BeanDefinition, so BeanDefinitionHolder is returned
public class BeanDefinitionHolder implements BeanMetadataElement {
private final BeanDefinition beanDefinition;
private final String beanName;
@Nullable
private final String[] aliases;
public BeanDefinitionHolder(BeanDefinition beanDefinition, String beanName) {
this(beanDefinition, beanName, (String[])null);
}
Copy the code
Going back to the original method, there are two steps in this method. The first step is parsing the bean (parsing the XML file to GenericBeanDefinition, which is an implementation of BeanDefinition, BeanDefinition is a property in BeanDefinitionHolder. Step is registration of beans. Let’s look at bean registration
Protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {/ / return properties in the configuration file (BeanDefinitionHolder contains BeanDefinition) BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder ! = null) {/ / no is empty, if the default label the child nodes of the custom attributes, need to custom tag parsed bdHolder = delegate. DecorateBeanDefinitionIfRequired (ele, bdHolder); After the try {/ / parsing is complete to register BeanDefinitionReaderUtils bdHolder. RegisterBeanDefinition (bdHolder, this.getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException var5) { this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5); } this.getreaderContext ().FireComponentRegistered (New BeanComponentDefinition(bdHolder)); }}Copy the code
RegisterBeanDefinition method
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { String beanName = definitionHolder.getBeanName(); / / use beanName registered registry as a unique identifier. The registerBeanDefinition (beanName definitionHolder. GetBeanDefinition ()); String[] aliases = definitionHolder.getAliases(); if (aliases ! = null) { String[] var4 = aliases; int var5 = aliases.length; for(int var6 = 0; var6 < var5; ++var6) { String alias = var4[var6]; registry.registerAlias(beanName, alias); }}}Copy the code
DefaultListableBeanFactory class for registration, the registration of understanding is through beanName form a map, beanName is key
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); if (beanDefinition instanceof AbstractBeanDefinition) { try { ((AbstractBeanDefinition)beanDefinition).validate(); } catch (BeanDefinitionValidationException var8) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var8); } } BeanDefinition existingDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName); if (existingDefinition ! = null) { if (! this.isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition); } if (existingDefinition.getRole() < beanDefinition.getRole()) { if (this.logger.isInfoEnabled()) { this.logger.info("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } else if (! beanDefinition.equals(existingDefinition)) { if (this.logger.isDebugEnabled()) { this.logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } else if (this.logger.isTraceEnabled()) { this.logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } / / beanDefinitionMap global variables is concurrent access problems / / in this step registered bean enclosing beanDefinitionMap. Put (beanDefinition beanName); } else { if (this.hasBeanCreationStarted()) { Map var4 = this.beanDefinitionMap; synchronized(this.beanDefinitionMap) { this.beanDefinitionMap.put(beanName, beanDefinition); List<String> updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; this.removeManualSingletonName(beanName); } } else { this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); this.removeManualSingletonName(beanName); } this.frozenBeanDefinitionNames = null; } if (existingDefinition == null && ! this.containsSingleton(beanName)) { if (this.isConfigurationFrozen()) { this.clearByTypeCache(); } } else { this.resetBeanDefinition(beanName); }}Copy the code