Exploring the Essentials of spring Container 1

Keywords: Programming xml Spring Java Session

1. Questions

  • 1. What is a spring container?

  • 2. How does the spring container start?

  • 3. What is the nature of the spring container?

  • 4. What role does the spring container play in the spring family?

  • 5. spring container design ideas?

2. Keyword

Container, Session, Context, Factory, Registry, Resolution, Definition, Initialization, Lazy Loading BeanFactory, BeanDefinition, ApplicationContext

3. Full Text Summary

The spring container is essentially a unit of definition that stores properties and methods describing different objects. When needed, objects are created according to the reflection mechanism, and then the described properties are initialized.It involves a series of sophisticated design patterns and implementation ideas that provide an excellent template for writing standard, high-quality code.This article seeks to discuss the core mechanisms of spring containers and to clarify the nature of spring containers with minimal code.

4. Architecture

4.1 Spring Overall Architecture

The above figure is the overall architecture of the Spring framework, from which we can see that the foundation of Spring is core container, which is what we call IOC container.This is the basis for the prosperity of AOP, DATA and WEB. In this chapter we discuss the foundation of the spring family, the spring container, which is the IOC container we mentioned above.All other spring components are built on containers, so we've temporarily removed all other component feature descriptions and only discussed IOC containers.

The three core jar packages of the spring container are beans, context, and core.Beans are the cornerstone of spring. Beans at the end of everything, contexts maintain the context of the application. If beans are actors, contexts are the stage, and cores are props.

4.1 Context ApplicationConext

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,        MessageSource, ApplicationEventPublisher, ResourcePatternResolver {    String getId();    String getApplicationName();    String getDisplayName();    long getStartupDate();    ApplicationContext getParent();    AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}
  • ApplicationConext: From the inheritance relationship of the class diagram, we see that the underlying class ApplicationConext inherits five capabilities: resource, message, event, environment, factory. ApplicationConext contains only simple read-only properties.

  • Configurable ApplicationContext: Inherits the life cycle management capabilities, while inheriting the ApplicationConext, expands the context's environment, events, and other write properties.

  • AbstractApplicationContext: Most of the capabilities are implemented in this class definition, which inherits the class load capability interface DefaultResourceLoader and Configurable ApplicationContext that reads and writes the context, and is parsed in detail by the process started by the ioc container.

  • GenericApplicationContext: Common context,

  • AnnotationConfigApplicationContext: Annotation configurable context,

  • GenericGroovyApplicationContext:groovy configuration file context,

  • GenericXml ApplicationContext: General xml profile context,

  • StaticApplicationContext: Message readable context,

  • AbstractRefreshableApplicationContext: Refreshable configurable context,

  • AbstractRefreshableConfigApplicationContext: Refreshable configurable context,

  • The context of the AbstractXmlApplicationContext:xml configuration file type,

  • ClassPathXmlAp-plicationContext: The terminal class path xml context,

  • FileSystemXmlApplicationContext: File system xml context,

4.2BeanFactory

spring's world is all about bean s.

  • AliasRegistry: Alias Registry

  • BeanFactory: Factory

  • BeanDefinitionRegistry:

DefaultListableBeanFactory, which converges so much of the upper level's capabilities, specifically includes the core BeanDefinitionRegistry and BeanFactory, which is the factory where bean s are defined and produced.

5. Process

The container launches the core process as shown below, which consists of creating an object after the container reads the configuration file, then initializing the object properties:

5.1 Startup Container

To explore spring's core container principles, you need to eliminate the interference of other advanced properties, build your project with the least jar packages, and then follow the container's starting process step by step.

  • Build Project: Create a new java project, introducing spring packages with minimal dependencies

New Test Startup Class Application

package com.alibaba.spring;import com.alibaba.spring.beans.Producer;import org.springframework.context.support.ClassPathXmlApplicationContext;/**
 * @author miumiu
 */public class Application {    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Producer producer = context.getBean(Producer.class);
        System.out.println("running the test case with name = " + producer.getCount());
    }
}
  • New spring Profile

    <?xml version="1.0" encoding="UTF-8"?><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-3.0.xsd">
        <bean name="producer" class="com.alibaba.spring.beans.Producer">
            <property name="count" value="10" />
        </bean></beans>
  • results of enforcement

    July 10, 2018 11:31:16 morning org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
    //Information: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@5197848c: startup date [Tue Jul 10 11:31:16 CST 2018]; root of context hierarchy
    //July 10, 2018 11:31:17 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
    //Information: Loading XML bean definitions from class path resource [applicationContext.xml]
    running the test case with name = 10

After these steps, we have successfully created the objects described in the configuration file using spring's IOC container, and we no longer need to create objects using the new form. Here's a workflow for dissecting the IOC container in depth.

5.2 Entry

  • Create the spring container context object, call the ClassPathXmlApplicationContext constructor, and pass in the configuration file path parameter

    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");/**
    * loading the definitions
    * from the given XML file and automatically refreshing the context
    */public ClassPathXmlApplicationContext(String configLocation) throws BeansException {    this(new String[] {configLocation}, true, null);
    }public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
                throws BeansException {    super(parent);
        setConfigLocations(configLocations);    if (refresh) {
            refresh(); //Core approach
        }
    }
  • Call the refresh() method to start the IOC container

        /**
        * Load or refresh the persistent representation of the configuration
        */
        public void refresh() throws BeansException, IllegalStateException {
            //Container restarts synchronous monitoring lock to prevent refresh from being repeated halfway through
            synchronized (this.startupShutdownMonitor) {
                // Prepare this context for refreshing.
                //Fill in profile placeholders, record container startup time and startup status
                prepareRefresh();
    
                 //Complete the process of defining the configuration file to the registry registration bean s, at which point the object has not been created
                // Tell the subclass to refresh the internal bean factory.
                ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
                // Prepare the bean factory for use in this context.
                //Configure class loader, customize special bean s, add BeanPostProcessor for callback
                prepareBeanFactory(beanFactory);
    
                try {
                    // Allows post-processing of the bean factory in context subclasses.
                    //The factory loads the configuration and calls back the PostProcessBeanFactory as a factory extension before initialization
                    postProcessBeanFactory(beanFactory);
    
                    // Invoke factory processors registered as beans in the context.
                    //Call the implementation of the extension interface PostProcessBeanFactory registered above, which is a list type for the extension interface
                    invokeBeanFactoryPostProcessors(beanFactory);
    
                    // Register bean processors that intercept bean creation.
                    // bean extension: postProcessBeforeInitialization and postProcessAfterInitialization
                     //Executed before and after Bean initialization, respectively
                    registerBeanPostProcessors(beanFactory);
    
                    // Initialize message source for this context.
                    //Initialize MessageSource object, internationalize
                    initMessageSource();
    
                    // Initialize event multicaster for this context.
                    //Initialize event broadcaster
                    initApplicationEventMulticaster();
    
                    // Initialize other special beans in specific context subclasses.
                    //Temporary hook method, which provides some special operations before initialization is complete, portal
                    onRefresh();
    
                    // Check for listener beans and register them.
                    //Register listener
                    registerListeners();
    
                    // Instantiate all remaining (non-lazy-init) singletons.
                    //Instantiate the bean s in the factory registry (unless lazily loaded, used to instantiate)
                    finishBeanFactoryInitialization(beanFactory);
    
                    // Last step: publish corresponding event.
                    //Initialize life cycle, broadcast events
                    finishRefresh();
                }
    
                catch (BeansException ex) {
                    if (logger.isWarnEnabled()) {
                        logger.warn("Exception encountered during context initialization - " +
                                "cancelling refresh attempt: " + ex);
                    }
    
                    // Destroy already created singletons to avoid dangling resources.
                    destroyBeans();
    
                    // Reset 'active' flag.
                    cancelRefresh(ex);
    
                    // Propagate exception to caller.
                    throw ex;
                }
    
                finally {
                    // Reset common introspection caches in Spring's core, since we
                    // might not ever need metadata for singleton beans anymore...
                    resetCommonCaches();
                }
            }
        }

5.3 Preparations

  • Initialization before container initialization

        protected void prepareRefresh() {        this.startupDate = System.currentTimeMillis();        this.closed.set(false);        this.active.set(true);        if (logger.isInfoEnabled()) {
                logger.info("Refreshing " + this);
            }        // Initialize any placeholder property sources in the context environment
             //Initialization Placeholder
            initPropertySources();        // Validate that all properties marked as required are resolvable
            // see ConfigurablePropertyResolver#setRequiredProperties
             //Verify Profile
            getEnvironment().validateRequiredProperties();        // Allow for the collection of early ApplicationEvents,
            // to be published once the multicaster is available...
            this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
        }

5.4 Create BeanFactory

  • Create BeanFactory, which is one of the two core modules of the entire IOC container startup process

    //AbstractApplicationContext.java

        protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {         //Close old factories and create new ones
            refreshBeanFactory();         //Return to the new factory created
            ConfigurableListableBeanFactory beanFactory = getBeanFactory();        if (logger.isDebugEnabled()) {
                logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
            }        return beanFactory;
        }
  • Reset BeanFactory, destroy if present, create if not present

    //AbstractRefreshableApplicationContext.java 120

        @Override
        protected final void refreshBeanFactory() throws BeansException {        //If BeanFactory() exists, it will be destroyed, that is, the objects stored in the Map in the factory will be cleared
            if (hasBeanFactory()) {
                destroyBeans();
                closeBeanFactory();
            }        try {             //Return to the newly created DefaultListableBeanFactory
                DefaultListableBeanFactory beanFactory = createBeanFactory();             //Factory identification id
                beanFactory.setSerializationId(getId());             //Set whether the container allows object overrides, circular dependencies
                customizeBeanFactory(beanFactory);
                loadBeanDefinitions(beanFactory);            synchronized (this.beanFactoryMonitor) {                this.beanFactory = beanFactory;
                }
            }        catch (IOException ex) {            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
            }
        }
  • Create BeanFactory, construct subclass object DefaultListableBeanFactory, we can see the importance of this class from the previous architecture section, which covers factory BeanFactory, object definition BeanDefinition, and registry AliasRegistry capabilities, is a complete object factory, the following is to use this factory to convert configuration file information into class definition information.Then the object is created and the attribute is assigned.

    //AbstractRefreshableApplicationContext.java 199

        protected DefaultListableBeanFactory createBeanFactory() {        return new DefaultListableBeanFactory(getInternalParentBeanFactory());
        }

5.5 Read Configuration File

  • Read xml configuration file

    //AbstractXmlApplicationContext.java 80

        protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {        // Create a new XmlBeanDefinitionReader for the given BeanFactory.
             //XML file reader instantiating a factory class
            XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);        // Configure the bean definition reader with this context's
            // resource loading environment.
            beanDefinitionReader.setEnvironment(this.getEnvironment());
            beanDefinitionReader.setResourceLoader(this);
            beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));        // Allow a subclass to provide custom initialization of the reader,
            // then proceed with actually loading the bean definitions.
             //Open xml file check to close subclasses of the implementation
            initBeanDefinitionReader(beanDefinitionReader);         //beanDefinitionReader Reader Load Resource File
            loadBeanDefinitions(beanDefinitionReader);
        }
  • Load resource file

    //AbstractXmlApplicationContext.java 120

        protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
            Resource[] configResources = getConfigResources();        if (configResources != null) {
                reader.loadBeanDefinitions(configResources);
            }         //CongLocations eventually resolves to the resource object configResources with the same effect as the branch above
            String[] configLocations = getConfigLocations();        if (configLocations != null) {
                reader.loadBeanDefinitions(configLocations);
            }
        }
  • Load all resource files in a loop

    //AbstractBeanDefinitionReader.java  177

        public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
            Assert.notNull(resources, "Resource array must not be null");        int counter = 0;        for (Resource resource : resources) {
                counter += loadBeanDefinitions(resource);
            }        return counter;
        }
  • Reader gets path from resource object and reads configuration file

    //XmlBeanDefinitionReader.java 303

        public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {        return loadBeanDefinitions(new EncodedResource(resource));
        }

    //XmlBeanDefinitionReader.java 314

        public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
            Assert.notNull(encodedResource, "EncodedResource must not be null");        if (logger.isInfoEnabled()) {
                logger.info("Loading XML bean definitions from " + encodedResource.getResource());
            }         //Use ThreadLocal to store profile paths
            Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();        if (currentResources == null) {
                currentResources = new HashSet<EncodedResource>(4);            this.resourcesCurrentlyBeingLoaded.set(currentResources);
            }        if (!currentResources.add(encodedResource)) {            throw new BeanDefinitionStoreException(                    "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
            }        try {
                InputStream inputStream = encodedResource.getResource().getInputStream();            try {
                    InputSource inputSource = new InputSource(inputStream);                if (encodedResource.getEncoding() != null) {
                        inputSource.setEncoding(encodedResource.getEncoding());
                    }                 //Open the file stream to read the contents of the file
                    return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
                }            finally {
                    inputStream.close();
                }
            }        catch (IOException ex) {            throw new BeanDefinitionStoreException(                    "IOException parsing XML document from " + encodedResource.getResource(), ex);
            }        finally {
                currentResources.remove(encodedResource);            if (currentResources.isEmpty()) {                this.resourcesCurrentlyBeingLoaded.remove();
                }
            }
        }
  • Read Profile Content

    //XmlBeanDefinitionReader.java 388

        protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
                throws BeanDefinitionStoreException {        try {            //Number of Document Files Generated by xml Files
                Document doc = doLoadDocument(inputSource, resource);            return registerBeanDefinitions(doc, resource);
            }        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);
            }
        }

5.6 Registration Objects

  • Register object, convert beans described by XML configuration file to BeanFactory's registry, return incremental number of beans

    //XmlBeanDefinitionReader.java 505

        public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
            BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();         //Number of Definition s already exist in the registry (description of object)
            int countBefore = getRegistry().getBeanDefinitionCount();         //Register the bean definition of the doc tree with the registry properties of the factory class
            documentReader.registerBeanDefinitions(doc, createReaderContext(resource));        return getRegistry().getBeanDefinitionCount() - countBefore;
        }
  • document reader, loads objects that have been converted into memory documents into the registry

    //DefaultBeanDefinitionDocumentReader.java 90

        public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {        this.readerContext = readerContext;
            logger.debug("Loading bean definitions");
            Element root = doc.getDocumentElement();
            doRegisterBeanDefinitions(root);
        }
  • Traverse document s to parse xml tags one by one

    //DefaultBeanDefinitionDocumentReader.java 116

        protected void doRegisterBeanDefinitions(Element root) {        // Any nested <beans> elements will cause recursion in this method. In
            BeanDefinitionParserDelegate parent = this.delegate;         //Create a tool to parse DOM tree objects BeanDefinitionParserDelegate
            this.delegate = createDelegate(getReaderContext(), root, parent);        if (this.delegate.isDefaultNamespace(root)) {             //If you do not include the <profile>tag, skip the operation, unnecessary method, skip
                String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);            if (StringUtils.hasText(profileSpec)) {
                    String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                            profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);                if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {                    if (logger.isInfoEnabled()) {
                            logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +                                "] not matching: " + getReaderContext().getResource());
                        }                    return;
                    }
                }
            }
    
            preProcessXml(root);//Reserve method, expand operation before parsing
            parseBeanDefinitions(root, this.delegate);//Core method, parsing DOM tree
            postProcessXml(root);//Reserve method, expanded operation after parsing
    
            this.delegate = parent;
        }

5.7 Parse Profile

  • Parse Memory DOM File Tree

    //DefaultBeanDefinitionDocumentReader.java 161

        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;                      //Default namespace containing http://www.springframework.org/schema/beans
                        if (delegate.isDefaultNamespace(ele)) {
                            parseDefaultElement(ele, delegate);
                        }                    else {                          //Non-default namespaces are <mvc/>, <context/>, <aop/>, etc.
                            delegate.parseCustomElement(ele);
                        }
                    }
                }
            }        else {
                delegate.parseCustomElement(root);
            }
        }
  • Resolve labels for default namespaces

    //DefaultBeanDefinitionDocumentReader.java 182

        private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {        if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
                importBeanDefinitionResource(ele);
            }        else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
                processAliasRegistration(ele);
            }        else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
                processBeanDefinition(ele, delegate);//Resolve labels with namespace bean s
            }        else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {            // recurse
                doRegisterBeanDefinitions(ele);
            }
        }
  • Parse label details, create a new BeanDefinition wrapper class, hold BeanDefinition references, beanName, and alias

    //DefaultBeanDefinitionDocumentReader.java 298

        protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {        //Convert DOM tree object to BeanDefinition wrapper class bdHolder
            BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);        if (bdHolder != null) {
                bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);            try {                // Register the final decorated instance.
                    BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
                }            catch (BeanDefinitionStoreException ex) {
                    getReaderContext().error("Failed to register bean definition with name '" +
                            bdHolder.getBeanName() + "'", ele, ex);
                }            // Send registration event.
                getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
            }
        }

    //BeanDefinitionParserDelegate.java 427

        public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {        return parseBeanDefinitionElement(ele, null);
        }

    //BeanDefinitionParserDelegate.java 436

        public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
            String id = ele.getAttribute(ID_ATTRIBUTE);
            String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
    
            List<String> aliases = new ArrayList<String>();        if (StringUtils.hasLength(nameAttr)) {
                String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
                aliases.addAll(Arrays.asList(nameArr));
            }
    
            String beanName = id;        if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
                beanName = aliases.remove(0);            if (logger.isDebugEnabled()) {
                    logger.debug("No XML 'id' specified - using '" + beanName +                        "' as bean name and " + aliases + " as aliases");
                }
            }        if (containingBean == null) {
                checkNameUniqueness(beanName, aliases, ele);
            }         //DOM tree label mapped to BeanDefinition object
            AbstractBeanDefinition beanDefinition = 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);                        // Register an alias for the plain bean class name, if still possible,
                            // if the generator returned the class name plus a suffix.
                            // This is expected for Spring 1.2/2.0 backwards compatibility.
                            String beanClassName = beanDefinition.getBeanClassName();                        if (beanClassName != null &&
                                    beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                                    !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                                aliases.add(beanClassName);
                            }
                        }                    if (logger.isDebugEnabled()) {
                            logger.debug("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);            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
            }        return null;
        }

    //BeanDefinitionParserDelegate.java 521

        public AbstractBeanDefinition parseBeanDefinitionElement(
                Element ele, String beanName, BeanDefinition containingBean) {        this.parseState.push(new BeanEntry(beanName));
    
            String className = null;        if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
                className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
            }        try {
                String parent = null;            if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
                    parent = ele.getAttribute(PARENT_ATTRIBUTE);
                }             //Create BeanDefinition object and set corresponding class name
                AbstractBeanDefinition bd = createBeanDefinition(className, parent);             //Parse tags inside xml into BeanDefinition objects one by one
                parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
                bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
    
                parseMetaElements(ele, bd);
                parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
                parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
    
                parseConstructorArgElements(ele, bd);
                parsePropertyElements(ele, bd);
                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;
        }
  • So far we have successfully mapped the label properties from a single xml profile into the BeanDefinitionHolder object, and then we have registered the BeanDefinition object into the factory registry

    //BeanDefinitionReaderUtils.java 143

        public static void registerBeanDefinition(
                BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
                throws BeanDefinitionStoreException {        // Register bean definition under primary name.
            String beanName = definitionHolder.getBeanName();         //Register the BeanDefinition object of the definitionHolder with the beanName to the registry
            registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());        // Register aliases for bean name, if any.
             //Register if there is an alias
            String[] aliases = definitionHolder.getAliases();        if (aliases != null) {            for (String alias : aliases) {
                    registry.registerAlias(beanName, alias);
                }
            }
        }
  • Register BeanDefinition Object

    //DefaultListableBeanFactory.java 793

        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 ex) {                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                            "Validation of bean definition failed", ex);
                }
            }
    
            BeanDefinition oldBeanDefinition;         //We've been fighting so long to convert xml to Definition and put it into beanDefinitionMap
            oldBeanDefinition = this.beanDefinitionMap.get(beanName);         //New xml should get empty
            if (oldBeanDefinition != null) {            if (!isAllowBeanDefinitionOverriding()) {                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                            "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
                            "': There is already [" + oldBeanDefinition + "] bound.");
                }            else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {                // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
                    if (this.logger.isWarnEnabled()) {                    this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +                            "' with a framework-generated bean definition: replacing [" +
                                oldBeanDefinition + "] with [" + beanDefinition + "]");
                    }
                }            else if (!beanDefinition.equals(oldBeanDefinition)) {                if (this.logger.isInfoEnabled()) {                    this.logger.info("Overriding bean definition for bean '" + beanName +                            "' with a different definition: replacing [" + oldBeanDefinition +                            "] with [" + beanDefinition + "]");
                    }
                }            else {                if (this.logger.isDebugEnabled()) {                    this.logger.debug("Overriding bean definition for bean '" + beanName +                            "' with an equivalent definition: replacing [" + oldBeanDefinition +                            "] with [" + beanDefinition + "]");
                    }
                }            this.beanDefinitionMap.put(beanName, beanDefinition);
            }        else {             //The initialization process should not allow instantiation
                if (hasBeanCreationStarted()) {                // Cannot modify startup-time collection elements anymore (for stable iteration)
                    synchronized (this.beanDefinitionMap) {                    this.beanDefinitionMap.put(beanName, beanDefinition);
                        List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
                        updatedDefinitions.addAll(this.beanDefinitionNames);
                        updatedDefinitions.add(beanName);                    this.beanDefinitionNames = updatedDefinitions;                    if (this.manualSingletonNames.contains(beanName)) {
                            Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
                            updatedSingletons.remove(beanName);                        this.manualSingletonNames = updatedSingletons;
                        }
                    }
                }            else {                 //The core step is to add a beanDefinition to the beanDefinition Map
                    // Still in startup registration phase
                    this.beanDefinitionMap.put(beanName, beanDefinition);                this.beanDefinitionNames.add(beanName);                this.manualSingletonNames.remove(beanName);
                }            this.frozenBeanDefinitionNames = null;
            }        if (oldBeanDefinition != null || containsSingleton(beanName)) {
                resetBeanDefinition(beanName);
            }
        }

 

 

 

 

 

 

 

 

Posted by pcw on Sat, 11 May 2019 02:10:41 -0700