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