Spring uses xml to start source parsing

Origin of this article Spring uses xml to start source parsing
Reprinted please indicate the source

Engineering preparation

  • Introducing Spring Minimum Dependency
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring.version>5.1.8.RELEASE</spring.version>

    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

    </dependencies>
  • applicationContext.xml configuration
<?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.xsd">
<bean id="myBean" class="org.ting.spring.study.App"/>
</beans>
  • Spring startup code
package org.ting.spring.study;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App 
{
    public static void main( String[] args ){
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        App myBean = (App) app.getBean("myBean");
        System.out.println(myBean);
    }
}

Understanding ClassPath Xml Application Context


This class is basically a constructor

As you can see, this one does not have any business logic code, but extends its functions by inheriting Abstract classes. The main business is in the parent class. Let's see how the constructor initializes the Spring container.

public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[] {configLocation}, true, null);
    }

Approach to this construction

public ClassPathXmlApplicationContext(
            String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
            throws BeansException {
         //Setting up parent container
        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
            refresh();
        }
    }

As you can see, this is the ClassPathXml ApplicatonContext instantiation method, which sets the parent container object, adds the configuration file path to the container and starts the container work.
The super(parent) method invokes the construction methods of the service parent class AbstractXml Application Context, AbstractRefreshableConfig Application Context, AbstractRefreshableApplicationContext and AbstractApplicationContext in turn.

    public AbstractApplicationContext(@Nullable ApplicationContext parent) {
        this();
        setParent(parent);
    }
@Override
    public void setParent(@Nullable ApplicationContext parent) {
        this.parent = parent;
        if (parent != null) {
            Environment parentEnvironment = parent.getEnvironment();
            if (parentEnvironment instanceof ConfigurableEnvironment) {
                getEnvironment().merge((ConfigurableEnvironment) parentEnvironment);
            }
        }
    }

This method calls the parent constructor up until the AbstractApplicationContext object. If the parameter is not empty, the parent context setting such as Environment setting is merged into the current container, and the two container configuration files are merged, which is commonly used in the web environment.

setConfigLocations

    public void setConfigLocations(@Nullable String... locations) {
        if (locations != null) {
            Assert.noNullElements(locations, "Config locations must not be null");
            this.configLocations = new String[locations.length];
            for (int i = 0; i < locations.length; i++) {
          //Processing path, replacing placeholder ${x} from environment variables
                this.configLocations[i] = resolvePath(locations[i]).trim(); 
            }
        }
        else {
            this.configLocations = null;
        }
    }

Add the path to the AbstractRefreshable Config Application Context configLocations property and drop the placeholder for the environment variable in the path to ensure that configLocaiton gets the available address.

Refesh Interpretation

@Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            //Preparing to refresh context objects
            prepareRefresh();

            // Create Spring Factory objects, empty caches, parse xml files, convert them into BeanDefinition and save them in the cache
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            //Initialize BeanFactory internal property values, add type conversion, and preprocessor
            prepareBeanFactory(beanFactory);

            try {
                // Empty method to allow word class implementation to view or modify the internal property values of beanFacore
                postProcessBeanFactory(beanFactory);

                // Register to instantiate BeanFactoryPostProcessor and execute all class interface methods
                invokeBeanFactoryPostProcessors(beanFactory);

                //Register all post processors
                registerBeanPostProcessors(beanFactory);

                //Initialize messageSource bean
                initMessageSource();

                //Initialization Multicast
                initApplicationEventMulticaster();

                // Empty method, let the word class initialize the special bean by itself
                onRefresh();

                // Initialize all event listeners, join multicast, broadcast events
                registerListeners();

                //Start all non-delayed singleton bean s 
                finishBeanFactoryInitialization(beanFactory);

                // Complete the application context initialization
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy successfully created bean s
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring's core, since we
                //Clear up all types of metadata collections such as annotation scanning, reflection, etc.
                resetCommonCaches();
            }
        }
    }

Now let's parse each method one by one.

prepareRefresh

protected void prepareRefresh() {
        // Switch to active.
        this.startupDate = System.currentTimeMillis();
        this.closed.set(false);
        this.active.set(true);

        if (logger.isDebugEnabled()) {
            if (logger.isTraceEnabled()) {
                logger.trace("Refreshing " + this);
            }
            else {
                logger.debug("Refreshing " + getDisplayName());
            }
        }

        // Initialize PropertySource without any processing by default, so that subclasses can be implemented
        initPropertySources();

        // Validate that all properties marked as required are resolvable:
        // see ConfigurablePropertyResolver#setRequiredProperties
        getEnvironment().validateRequiredProperties();

        // Store pre-refresh ApplicationListeners...
        if (this.earlyApplicationListeners == null) {
            this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
        }
        else {
            // Reset local application listeners to pre-refresh state.
            this.applicationListeners.clear();
            this.applicationListeners.addAll(this.earlyApplicationListeners);
        }

        // Allow for the collection of early ApplicationEvents,
        // to be published once the multicaster is available...
        this.earlyApplicationEvents = new LinkedHashSet<>();
    }

Setting startup time, closing tag setting false, active switch setting true, initPropertySources(), itself is an empty method, implemented by subclasses themselves, allowing subclasses to modify the Properties Sources object properties of Configurable Environment before the container is created. The encapsulation interface of Property Sourcesname/value key pair is mainly used to assemble configuration variables. Although neither ClassPathXmlApplicatonContext nor its parent implements this method, in Spring MVC, GenericWebApplicationContext implements the initPropertySources method, merging servletContext configuration variables into ProertySources. Next, look at getEnvironment().validateRequiredProperties(). This method is implemented in

validateRequiredProperties

    @Override
    public void validateRequiredProperties() {
        MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();
        for (String key : this.requiredProperties) {
            if (this.getProperty(key) == null) {
                ex.addMissingRequiredProperty(key);
            }
        }
        if (!ex.getMissingRequiredProperties().isEmpty()) {
            throw ex;
        }
    }

Mainly check the key value in ProertySources, whether there is any mismatch. In fact, this major check comes from an initPropertySources() method security measure. For example, the father let his son do something, he did not interfere at all, but he would sneak to see how things were going? If you can't do it, give your son a good beating.

Configurable Listable BeanFactory initialization

This part should be the core function of the whole code parsing. This class is what we often call Spring container, the implementation of the Spring factory DefaultListable BeanFactory. Mainly responsible for bean registration instantiation, bean lookup, bean alias, bean destruction. Instantiating this object here also begins to show that the Spring lifecycle has officially begun. Here is the inheritance relationship of DefaultListableBeanFactory

View the obtainFreshBeanFactory method details

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        refreshBeanFactory();
        return getBeanFactory();
    }

refreshBeanFactory mainly clears the Configurable Listable BeanFactory bean cache and re-instantiates it.

refreshBeanFactory

This method is in AbstractRefreshable Application Context

protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) { //Determine whether Configurable Listable BeanFactory has been created 
            destroyBeans();
            closeBeanFactory();
        }
        try {
                        //Instantiate the new DefaultListable BeanFactory (parent) with a constructor
            DefaultListableBeanFactory beanFactory = createBeanFactory(); 
            beanFactory.setSerializationId(getId());
                //Spring factory custom settings, whether to run registered beans overwritten by the same beanName, default is true, set whether to allow circular references between beans - and try to automatically resolve it by default is also true
            customizeBeanFactory(beanFactory);
            //Start parsing the xml configuration file and register BeanDefinition. Here's a detailed analysis
            loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }

First, determine whether the Configurable Listable BeanFactory object has been created successfully. If it already exists, execute the destruction of registered beans in the Spring container, re-instantiate the Configurable Listable BeanFactory object, set the id, set the rename of the beanFactory bean, and depend on the solution. Start loading the xml configuration file, register BeanDefinition, and point the instantiated BeanFactory guide to this.beanFactory.

Look mainly at destroy Beans ()

protected void destroyBeans() {
        getBeanFactory().destroySingletons();
    }

The destroySingletons method of Configurable Listable BeanFactory is called, and the implementation class of the interface is DefaultListable BeanFactory.

@Override
    public void destroySingletons() {
        super.destroySingletons();
        updateManualSingletonNames(Set::clear, set -> !set.isEmpty());
        clearByTypeCache();
    }
destroySingletons

super.destroySingletons() calls the destroySingletons method of DefaultSingleton BeanRegistry

public void destroySingletons() {
        if (logger.isTraceEnabled()) {
            logger.trace("Destroying singletons in " + this);
        }
        synchronized (this.singletonObjects) {
            this.singletonsCurrentlyInDestruction = true;
        }

        String[] disposableBeanNames;
        synchronized (this.disposableBeans) { //Convert map key to string array
            disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
        }
        for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
            destroySingleton(disposableBeanNames[i]);
        }

        this.containedBeanMap.clear();
        this.dependentBeanMap.clear();
        this.dependenciesForBeanMap.clear();

        clearSingletonCache();
    }
destroySingleton
public void destroySingleton(String beanName) {
        // Remove a registered singleton of the given name, if any.
        removeSingleton(beanName);

        // Destroy the corresponding DisposableBean instance.
        DisposableBean disposableBean;
        synchronized (this.disposableBeans) {
            disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);
        }
        destroyBean(beanName, disposableBean);
    }

View the removeSingleton method

protected void removeSingleton(String beanName) {
        synchronized (this.singletonObjects) {
            this.singletonObjects.remove(beanName);
            this.singletonFactories.remove(beanName);
            this.earlySingletonObjects.remove(beanName);
            this.registeredSingletons.remove(beanName);
        }
    }

These are the internal containers. Look at their main uses.

    /**Caching singleton bean objects: beanName corresponding bean objects */
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    /**Cache Singleton Factory: beanName corresponds to the bean factory entity. */
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

    /** Cache beans early objects, mainly beans registered entity-dependent objects: beanName corresponding entity objects */
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

    /**beanName has been successfully registered and saved in registration order */
    private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
destroyBean
    protected void destroyBean(String beanName, @Nullable DisposableBean bean) {
        // Trigger destruction of dependent beans first...
        Set<String> dependencies;
        synchronized (this.dependentBeanMap) {
            // Within full synchronization in order to guarantee a disconnected Set
            dependencies = this.dependentBeanMap.remove(beanName);
        }
        if (dependencies != null) {
            if (logger.isTraceEnabled()) {
                logger.trace("Retrieved dependent beans for bean '" + beanName + "': " + dependencies);
            }
            for (String dependentBeanName : dependencies) {
                destroySingleton(dependentBeanName);
            }
        }

        // Actually destroy the bean now...
        if (bean != null) {
            try {
                bean.destroy();
            }
            catch (Throwable ex) {
                if (logger.isInfoEnabled()) {
                    logger.info("Destroy method on bean with name '" + beanName + "' threw an exception", ex);
                }
            }
        }

        // Trigger destruction of contained beans...
        Set<String> containedBeans;
        synchronized (this.containedBeanMap) {
            // Within full synchronization in order to guarantee a disconnected Set
            containedBeans = this.containedBeanMap.remove(beanName);
        }
        if (containedBeans != null) {
            for (String containedBeanName : containedBeans) {
                destroySingleton(containedBeanName);
            }
        }

When deleting Disposable Bean instances, get the dependent instances under the bean and remove them one by one. Finally, the Spring container dependent entities are removed one by one. Next, look at the closeBeanFactory() approach

Load Bean Definitions parsing

    @Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        // Create a new XmlBeanDefinitionReader for the given BeanFactory.
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        // Configure the bean definition reader with this context's
        // resource loading environment.
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
         //xml file constraint checking
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

        // Allow a subclass to provide custom initialization of the reader,
        // Setting up xml checking mode
        initBeanDefinitionReader(beanDefinitionReader);
                //Start parsing the xml transformation BeanDefinition
        loadBeanDefinitions(beanDefinitionReader);
    }

The instantiated XmlBeanDefinitionReader parses the resource file xml into BeanDefinition and assigns Spring context objects to object attributes. Loading Bean Definitions converts xml files into Document objects. Because this part is too cumbersome, we need to get ResouceLoader according to the file name, then get the file stream object, parse xml into Document. We think that we should omit these code parsing, mainly focus on how Document is converted into Bean Definition, in DefaultBean Definition Document. MentReader implementation.

doRegisterBeanDefinitions
    protected void doRegisterBeanDefinitions(Element root) {
        // Any nested <beans> elements will cause recursion in this method. In
        // order to propagate and preserve <beans> default-* attributes correctly,
        // keep track of the current (parent) delegate, which may be null. Create
        // the new (child) delegate with a reference to the parent for fallback purposes,
        // then ultimately reset this.delegate back to its original (parent) reference.
        // this behavior emulates a stack of delegates without actually necessitating one.
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = createDelegate(getReaderContext(), root, parent);

        if (this.delegate.isDefaultNamespace(root)) {
            String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
                    //Determine the file profile property and convert it to array
            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;
                }
            }
        }
        //Run the custom implementation class to preprocess the xml file, empty method, and let the subclass implement.
        preProcessXml(root);
        parseBeanDefinitions(root, this.delegate);
       //Run custom autonomous solid methods, modify xml properties, empty methods.  
        postProcessXml(root);

        this.delegate = parent;
    }

BeanDefinition ParserDelegate mainly parses Document namespaces, tag elements, attributes, and converts xml tags into objects.

prseBeanDefinitions
    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)) {
                                              //Register BeanDefinition
                        parseDefaultElement(ele, delegate);
                    }
                    else {
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
            delegate.parseCustomElement(root);
        }
    }

Loop through the subtags of beans, conform to the "import", "alias", "bean" namespace, and enter the tag parsing link.

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);
        }
        else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
            // recurse
            doRegisterBeanDefinitions(ele);
        }
    }

Look mainly at bean tag parsing

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        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));
        }
    }

This method returns the xml parsing to the BeanDefinition object. If the object is not empty, continue to parse the element's custom attributes, and set the element's custom attributes to the newly created BeanDefiniton object. Finally, broadcast and register the BeanDefinition object. I don't know much about how to generate BeanDefiniton objects. After all, there's a lot of space in it. I'll devote a chapter to it later.

Analysis of prepareBeanFactory Method

The prepareBeanFactory method mainly configures the property settings of BeanFactory class loader, Spring el expression implementation, bean preprocessor and so on. The main logic is detailed in the following code

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // Tell the internal bean factory to use the context's class loader etc.
    //Set up the factory class loader beanFactory.setBeanClassLoader(getClassLoader());
        //Setting Spring el expression implementation 
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
       //Add Attribute Converter
        beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
        /*
         * Add a post processor implementation, if the corresponding Aware interface is implemented, then inject the corresponding resources
         * 1. EnvironmentAware
         * 2. EmbeddedValueResolverAware
         * 3. ResourceLoaderAware
         * 4. ApplicationEventPublisherAware
         * 5. MessageSourceAware
         * 6. ApplicationContextAware
         */
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
          //Ignore the automatic injection of these classes, corresponding to the above post-processor
        beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
        beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
        beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
        beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

              //Cache Spring internal objects and register them in containers.
        beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
        beanFactory.registerResolvableDependency(ResourceLoader.class, this);
        beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
        beanFactory.registerResolvableDependency(ApplicationContext.class, this);

        // Preprocessing of Registered Event Listener
        beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

        // Register the aop preprocessor if there is an AOP bean name
        if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            // Set a temporary ClassLoader for type matching.
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }

        // Register default environment beans.
        if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
                //Register bean s with Spring containers
            beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
        }
        if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) { //Register System Environment Variables
            beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
        }
        if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
            beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());0

        }
    }

BeanPostProcessor

The addBeanPostProcessor method mainly adds BeanPostProcessor interface implementation classes. Bean post-processor mainly performs some processing before and after bean initialization. spring bean creation is delegated to a large post-processor to create.

public interface BeanPostProcessor {

    /**
     * bean Before creation, the bean is processed and the processed entity is returned to the BeanFactory container
     */
    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    /**
     * bean After creation, processing bean s is equivalent to enhancing the functionality that has already been created.
     */
    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

}

ApplicationContextAwareProcessor

    @Override
    @Nullable
    public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
        AccessControlContext acc = null;

        if (System.getSecurityManager() != null &&
                (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
                        bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
                        bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
            acc = this.applicationContext.getBeanFactory().getAccessControlContext();
        }

        if (acc != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                invokeAwareInterfaces(bean);
                return null;
            }, acc);
        }
        else {
            invokeAwareInterfaces(bean);
        }

        return bean;
    }

    private void invokeAwareInterfaces(Object bean) {
        if (bean instanceof Aware) {
            if (bean instanceof EnvironmentAware) {
                ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
            }
            if (bean instanceof EmbeddedValueResolverAware) {
                ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
            }
            if (bean instanceof ResourceLoaderAware) {
                ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
            }
            if (bean instanceof ApplicationEventPublisherAware) {
                ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
            }
            if (bean instanceof MessageSourceAware) {
                ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
            }
            if (bean instanceof ApplicationContextAware) {
                ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
            }
        }
    }

The above logic determines whether the ready initialization bean s implement the interfaces of EnvironmentAware, Embedded Value Resolver Aware, Resource Loader Aware, Application Event Publisher Aware, MessageSourceAware. ApplicationContextAware. If so, directly execute the interface method and inject the Spring factory method into the properties. This also resolves the above settings for registerResolvable Dependency Dependency Injection Ignorance.

postProcessBeanFactory

There is no implementation in the postProcessBeanFactory method, mainly allowing subclasses to add special beans into the container before the Spring Factory initializes the beans, such as the BeanPostProcessors interface implementation class. By this time Spring has parsed the xml, and you need to add some beans to the container, so you can implement this method.

invokeBeanFactoryPostProcessors

The BeanFactoryPostProcessors interface is similar to BeanPostProcessor in that it can be used to process bean definitions or modify bean metadata before bean initialization. You can configure multiple BeanFactoryPostProcessors and use the Order interface to control the execution order. Source code display

    protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        //Execute BeanFactoryPostProcessors to execute methods from objects already instantiated in containers
        PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

        if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {//Determine whether AOP support is required and register the AOP preprocessor
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }
    }

invokeBeanFactoryPostProcessors

public static void invokeBeanFactoryPostProcessors(
            ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

        // Invoke BeanDefinitionRegistryPostProcessors first, if any.
        Set<String> processedBeans = new HashSet<>();

        if (beanFactory instanceof BeanDefinitionRegistry) {  //Forced type BeanDefinition RegistryPostProcessor interface needs to be used
            BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
            List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
            List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
              //Traversing through all BeanFactoryPostProcessors, the BeanFactoryPostProcessor type and the BeanDefinition RegistryPostProcessor type are put into unused containers, respectively.
             //And the BeanDefinition RegistryPostProcessor interface method is executed.
            for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
                if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                    BeanDefinitionRegistryPostProcessor registryProcessor =
                            (BeanDefinitionRegistryPostProcessor) postProcessor;
                    registryProcessor.postProcessBeanDefinitionRegistry(registry); //Execute interface methods, refer to or modify bean metadata
                    registryProcessors.add(registryProcessor);
                }
                else {
                    regularPostProcessors.add(postProcessor);
                }
            }

            // Do not initialize FactoryBeans here: We need to leave all regular beans
            // uninitialized to let the bean factory post-processors apply to them!
            // Separate between BeanDefinitionRegistryPostProcessors that implement
            // PriorityOrdered, Ordered, and the rest.
            List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

            // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
              //Get all bean Definition Registry PostProcessor type beans in the factory
            String[] postProcessorNames =
                    beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            for (String ppName : postProcessorNames) {
                if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    processedBeans.add(ppName);
                }
            }
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);
                //Execute all Bean Definition Registry PostProcessors interface methods in the collection
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            currentRegistryProcessors.clear();

            // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
            postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            for (String ppName : postProcessorNames) {
                if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    processedBeans.add(ppName);
                }
            }
                   //Sort the order in the collection according to the order interface     
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            currentRegistryProcessors.clear();

            // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
            boolean reiterate = true;
            while (reiterate) {
                reiterate = false;
                postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
                for (String ppName : postProcessorNames) {
                    if (!processedBeans.contains(ppName)) {
                        currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                        processedBeans.add(ppName);
                        reiterate = true;
                    }
                }
                sortPostProcessors(currentRegistryProcessors, beanFactory);
                registryProcessors.addAll(currentRegistryProcessors);
                invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
                currentRegistryProcessors.clear();
            }

            // Now, invoke the postProcessBeanFactory callback of all processors handled so far.
            invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
            invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
        }

        else {
            // Invoke factory processors registered with the context instance.
            invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
        }

        // Do not initialize FactoryBeans here: We need to leave all regular beans
        // uninitialized to let the bean factory post-processors apply to them!
        String[] postProcessorNames =
                beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

        // Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
        // Ordered, and the rest.
        List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
        List<String> orderedPostProcessorNames = new ArrayList<>();
        List<String> nonOrderedPostProcessorNames = new ArrayList<>();
        for (String ppName : postProcessorNames) {
            if (processedBeans.contains(ppName)) {
                // skip - already processed in first phase above
            }
            else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
            }
            else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
                orderedPostProcessorNames.add(ppName);
            }
            else {
                nonOrderedPostProcessorNames.add(ppName);
            }
        }

        // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
        sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
        invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

        // Next, invoke the BeanFactoryPostProcessors that implement Ordered.
        List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
        for (String postProcessorName : orderedPostProcessorNames) {
            orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
        }
        sortPostProcessors(orderedPostProcessors, beanFactory);
        invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

        // Finally, invoke all other BeanFactoryPostProcessors.
        List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
        for (String postProcessorName : nonOrderedPostProcessorNames) {
            nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
        }
        invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

        // Clear cached merged bean definitions since the post-processors might have
        // modified the original metadata, e.g. replacing placeholders in values...
        beanFactory.clearMetadataCache();
    }

    

It looks like a lot of code, but it's a very simple logic.

  1. Traversing through all BeanFactoryPostProcessor collections, the BeanDefinition RegistryPostProcessor is first taken out, and the interface method is executed, and then placed into the registryProcessors container.
  2. BeanFactory obtains all bean name arrays of BeanDefinition RegistryPostProcessor type, traverses the cyclic data, determines whether there is a PriorityOrdered interface, joins the container, and reorders according to the interface, traverses all classes of the container, executes the interface method, and joins the registryProcessors container.
  3. In order to obtain the bean name array of all BeanDefinition RegistryPostProcessor types in the container, loop through the bean name to extract the implementation of the Ordered interface, sort the collection according to the Orderd order, execute the interface method in turn, and add it to the registryProcessors container.
  4. All remaining Bean Definition Registry Post Processors are added to the Registry Processors container. Execute all BeanFactoryPostProcessor interface methods in the registryProcessors container.
  5. BeanFactoryPostProcessor also follows the above idea, first filters and sorts the execution interface method.

Looking at this, I have a question, how did these interface objects come into being? Spring factories did not start instantiating objects, and Spring only went on to convert xml into beanDefinition, which could not be obtained from Spring factories.

BeanFactoryPostProcessor instantiation process

The main way to instantiate bean s is in AbstractBeanFactory

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
            @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
              // Extract & Extract the corresponding beanName 
        final String beanName = transformedBeanName(name);
        Object bean;

        // Getting objects in the cache
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {
            if (logger.isTraceEnabled()) {
                if (isSingletonCurrentlyInCreation(beanName)) {
                    logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                            "' that is not fully initialized yet - a consequence of a circular reference");
                }
                else {
                    logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
                }
            }
                 //To determine whether the object in the cache is the correct bean instantiation, if it is a FactoryBean interface object, call the interface method to get the bean instance  
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }

        else {
            // If the bean Name is prototpe or scope type and is being created, throw an exception directly
            if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }

            // Attempt to get it in the parent container
            BeanFactory parentBeanFactory = getParentBeanFactory();
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                // No, try to modify the bean Name name and try again.
                String nameToLookup = originalBeanName(name);
                if (parentBeanFactory instanceof AbstractBeanFactory) {
                    return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                            nameToLookup, requiredType, args, typeCheckOnly);
                }
                else if (args != null) {
                    // Delegation to parent with explicit args.
                    return (T) parentBeanFactory.getBean(nameToLookup, args);
                }
                else if (requiredType != null) {
                    // No args -> delegate to standard getBean method.
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
                else {
                    return (T) parentBeanFactory.getBean(nameToLookup);
                }
            }
              //If you just do type checking and do not instantiate, this will add bean s to the creation record
            if (!typeCheckOnly) {
                markBeanAsCreated(beanName);
            }

            try {  
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                        //Judging that BeanDefinition type is not an abstract class
                checkMergedBeanDefinition(mbd, beanName, args);

                // Get bean metadata all dependent beans 
                String[] dependsOn = mbd.getDependsOn();
                if (dependsOn != null) {
                    for (String dep : dependsOn) {
                        if (isDependent(beanName, dep)) { //Check for dependencies
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                        }
                        //Adding dependencies and dependencies
                        registerDependentBean(dep, beanName);
                        try {
                            getBean(dep); //Instantiate Creating Dependent Beans
                        }
                        catch (NoSuchBeanDefinitionException ex) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                        }
                    }
                }

                // Create singleton objects
                if (mbd.isSingleton()) {
                    sharedInstance = getSingleton(beanName, () -> {
                        try {
                            //Specifically create the bean method, which is implemented by the subclass AbstractAutowireCapableBeanFactory
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            destroySingleton(beanName);
                            throw ex;
                        }
                    });
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }

                else if (mbd.isPrototype()) {
                    // It's a prototype -> create a new instance.
                    Object prototypeInstance = null;
                    try {
                                          //Add Create Records
                        beforePrototypeCreation(beanName);
                        prototypeInstance = createBean(beanName, mbd, args);
                    }
                    finally {
                                         //Delete record
                        afterPrototypeCreation(beanName);
                    }
                    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                }

                else {
                    String scopeName = mbd.getScope();
                    final Scope scope = this.scopes.get(scopeName);
                    if (scope == null) {
                        throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                    }
                    try {
                        Object scopedInstance = scope.get(beanName, () -> {
                            beforePrototypeCreation(beanName);
                            try {
                                return createBean(beanName, mbd, args);
                            }
                            finally {
                                afterPrototypeCreation(beanName);
                            }
                        });
                        bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                    }
                    catch (IllegalStateException ex) {
                        throw new BeanCreationException(beanName,
                                "Scope '" + scopeName + "' is not active for the current thread; consider " +
                                "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                                ex);
                    }
                }
            }
            catch (BeansException ex) {
                cleanupAfterBeanCreationFailure(beanName);
                throw ex;
            }
        }

        // Type checks show that bean s may be String types, but need to be converted to Integer types
        if (requiredType != null && !requiredType.isInstance(bean)) {
            try {
                          //Use Type Converter
                T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
                if (convertedBean == null) {
                    throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
                }
                return convertedBean;
            }
            catch (TypeMismatchException ex) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Failed to convert bean '" + name + "' to required type '" +
                            ClassUtils.getQualifiedName(requiredType) + "'", ex);
                }
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
        }
        return (T) bean;
    }

This is Spring's concrete process of creating beans, but there are still many details that have not been expressed. Looking at so many source codes, we all know that a method can not put so much logic into it. Later, I will have the opportunity to go into each method and explain it in detail. This paper summarizes the whole journey of Spring to create beans.

  1. Processing beanName removes the modifier of FactoryBean, which translates "& name" into "name". Convert alias name to a real bean Name.
  2. If it's a singleton, try loading beans from the cache. Processing the beans in the cache, only the most original beans are recorded in the cache, and must be the beans we ultimately want. We need getObjectForBean Instance to do this.
  3. Prototype Dependency Check
  4. Try to get the bean from the parent container if the parent container is not empty and contains the bean Name.
  5. Get all dependent beans under bean Name and instantiate all dependent beans
  6. The bean s are instantiated separately according to the object scope.
  7. After the instantiation, the object is converted to a requiredType given type.

registerBeanPostProcessors

Register all BeanPostProcessor post-processing classes. This is just registration, and no interface method is executed. The process is very similar to the BeanFactoryPostProcessor above. Look at the concrete code logic in PostProcessor Registration Delegate and notice the similarities with the above code.

public static void registerBeanPostProcessors(
            ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
           //Get all BeanPostProcessor beanName by type 
        String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

        // Registered BeanPostProcessor Checker is just an info log information printing class
        // When a bean is being created by BeanPostProcessor, information is printed
        // This bean cannot be of BeanPostProcessor type
        int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
        beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

        // Use PriorityOrdered Sort bean Execution Order
        List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
               //MergedBean Definition PostProcessor Interface Container
        List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
              //Sort bean execution order using Ordered interface
        List<String> orderedPostProcessorNames = new ArrayList<>();
              // Default sequencing
        List<String> nonOrderedPostProcessorNames = new ArrayList<>();
        for (String ppName : postProcessorNames) {
            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { //Matching type
                BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
                priorityOrderedPostProcessors.add(pp);
                if (pp instanceof MergedBeanDefinitionPostProcessor) {
                    internalPostProcessors.add(pp);
                }
            }
            else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
                orderedPostProcessorNames.add(ppName);
            }
            else {
                nonOrderedPostProcessorNames.add(ppName);
            }
        }

        //Register PriorityOrdered Priority First
        sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
               //Just register the processor, not call the method
        registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

        // Then register Ordered type prioritization
        List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
        for (String ppName : orderedPostProcessorNames) {
            BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
            orderedPostProcessors.add(pp);
            if (pp instanceof MergedBeanDefinitionPostProcessor) {
                internalPostProcessors.add(pp);
            }
        }
        sortPostProcessors(orderedPostProcessors, beanFactory);
        registerBeanPostProcessors(beanFactory, orderedPostProcessors);

        // Register all regular BeanPost Processors.
        List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
        for (String ppName : nonOrderedPostProcessorNames) {
            BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
            nonOrderedPostProcessors.add(pp);
            if (pp instanceof MergedBeanDefinitionPostProcessor) {
                internalPostProcessors.add(pp);
            }
        }
        registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

        // Finally register the MergedBeanDefinitionPostProcessor type
        sortPostProcessors(internalPostProcessors, beanFactory);
        registerBeanPostProcessors(beanFactory, internalPostProcessors);

        // Register Application Listener Post Processor
        // Add to all processor chains
        beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
    }

BeanPostProcessor registration process is very similar to BeanFactoryPostProcessor above.

  1. Obtain all post processor beanName from BeanPostProcessor
  2. Create a BeanPostProcessorChecker object based on the length of the beanName array and register it in the container.
  3. Create different processor containers according to Priority Ordered, MergedBean Definition Post Processor, Ordered, etc.
  4. Register processors according to different types of sorting

initMessageSource

Initialize the information resources class, Spring internal internationalization support. The logic is very simple. First, judge whether there is a message Source in the container and register the bean s directly. Otherwise, Spring registers Delegating Message Source internally. I won't release the code. Interested students will check it by themselves.

initApplicationEventMulticaster

Initialize the Application Event Multicaster Event Multicaster Event Multicaster, mainly to determine whether the user has customized the Event Multicaster, and directly use the user-defined Multicaster. If there is no user-defined multicast, Simple Application Event Multicaster is used by default, and the code is omitted.

onRefresh

Initialize other special bean s, which are implemented by subclasses themselves. Here we use the template method to design patterns, so that users can expand new functions.

registerListeners

Register all listeners that implement the ApplicationListeners interface and add them to the multicast just initialized above. Get all the event sets and publish them to the multicast, which then broadcasts them to the listener listening for the specified event.

    protected void registerListeners() {
        // Register statically specified listeners first.
        for (ApplicationListener<?> listener : getApplicationListeners()) {
            getApplicationEventMulticaster().addApplicationListener(listener);
        }

        // Do not initialize FactoryBeans here: We need to leave all regular beans
        // uninitialized to let post-processors apply to them!
        String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
        for (String listenerBeanName : listenerBeanNames) {
            getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
        }

        // Publish early application events now that we finally have a multicaster...
        Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
        this.earlyApplicationEvents = null;
        if (earlyEventsToProcess != null) {
            for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
                getApplicationEventMulticaster().multicastEvent(earlyEvent);
            }
        }
    }

finishBeanFactoryInitialization

This method is that we parse the Spring IOC core, initialize all Spring bean s, see so much code, and finally we want to understand the most part, directly on the code.

    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        // Initialize conversion service for type conversion
        if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
                beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
            beanFactory.setConversionService(
                    beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
        }

        //If there is no post processor, the embedded value parser is supported by default.
        // For example, any one registered before the Property Placeholder Configurer bean
        // Mainly used for placeholder parsing
        if (!beanFactory.hasEmbeddedValueResolver()) {
            beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
        }

        // Initialize all AOP proxy objects before all bean s are initialized
        String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
        for (String weaverAwareName : weaverAwareNames) {
            getBean(weaverAwareName);
        }

        // Cancel the temporary class loader and close the type lookup beanFactory.setTempClassLoader(null);

        //Freeze all bean Definition features
        beanFactory.freezeConfiguration();

        // Initialize non-delayed singleton beans (create all beans)
        beanFactory.preInstantiateSingletons();
    }
  1. If you determine whether there is a conversionService in the container and the type must be ConversionService, instantiate the bean. ConversionService interface is also a type converter.
  2. Determine whether there is a StringValueResolver type bean in the container, and no one is registered manually.
  3. Initialize all AOP notification types.

4. Freeze all bean metadata features and do not allow any modifications.

  1. Instantiate all non-delayed singleton bean s

preInstantiateSingletons

public void preInstantiateSingletons() throws BeansException {
        if (logger.isTraceEnabled()) {
            logger.trace("Pre-instantiating singletons in " + this);
        }

        // Traversing through all beans Definition Names, copy ing to the information list
        List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

        // Instantiate all non-delayed bean s 
        for (String beanName : beanNames) {
            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                if (isFactoryBean(beanName)) {// Determining FactoryBean Interface Type Beans 
                    Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                    if (bean instanceof FactoryBean) {
                        final FactoryBean<?> factory = (FactoryBean<?>) bean;
                        boolean isEagerInit;
                        if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                            isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
                                            ((SmartFactoryBean<?>) factory)::isEagerInit,
                                    getAccessControlContext());
                        }
                        else {
                            isEagerInit = (factory instanceof SmartFactoryBean &&
                                    ((SmartFactoryBean<?>) factory).isEagerInit());
                        }
                        if (isEagerInit) {
                            getBean(beanName);
                        }
                    }
                }
                else {
                    getBean(beanName);
                }
            }
        }

        // Implement Smart Initializing Singleton interface in execution bean, execute interface method, and execute after successful initialization with singleton bean
        for (String beanName : beanNames) {
            Object singletonInstance = getSingleton(beanName);
            if (singletonInstance instanceof SmartInitializingSingleton) {
                final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
                if (System.getSecurityManager() != null) {
                    AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                        smartSingleton.afterSingletonsInstantiated();
                        return null;
                    }, getAccessControlContext());
                }
                else {
                    smartSingleton.afterSingletonsInstantiated();
                }
            }
        }
    }

finishRefresh

    protected void finishRefresh() {
        // Empty Resource Cache in Container
        clearResourceCaches();

        // Initialize Lifecycle Processor and register with Spring container
        initLifecycleProcessor();

        //Call the Lifecycle Processor onRefresh method just registered above
        getLifecycleProcessor().onRefresh();

        // Publish Application Context to complete initialization events
        publishEvent(new ContextRefreshedEvent(this));

        // Initialize LiveBeansView registration into the container if spring.liveBeansView.mbeanDomain exists in the configuration file
        LiveBeansView.registerApplicationContext(this);
    }

This shows that Spring's process of creating bean s is almost complete, but there are still many details that are not shown, because the space is too much. It can be seen that what I said before is still more detailed, but after a brief analysis of some methods, the space is really too long. If there's anything wrong or not, please point it out. Let's study and discuss it together.

Tags: Java Spring xml Junit REST

Posted on Fri, 13 Sep 2019 02:12:15 -0700 by glennn3