preface

This chapter is mainly composed of the following parts:

  • Container initialization entry in Spring
  • The most classic ClassPathXmlApplicationContext, for example, to explain in detail the initialization process of the Spring IoC container

In the process of learning the source code, I want to emphasize two points:

  1. Must learn to grasp the key points, the core class, the core method, the core steps.
  2. Understand the naming of classes, variables, and method names. Spring source naming is very specific and often self-explanatory
  3. Be sure to read the Java Doc. Again, the Java DOC description for this top-level framework is very detailed

The Spring container initializes the entry

Starting the container is actually the action of instantiating the ApplicationContext. It’s just that there may be different forms of expression in different situations.

  1. ClassPathXmlApplicationContext with XML configuration
ApplicationContext context = new ClassPathXmlApplicationContext(applicationContext.xml");
Copy the code
  1. AnnotationConfigApplicationContext through Java config class configuration
@Configuration
@ComponentScan("ric.study.demo.ioc")
public class BeanDemoConfig {
    public static void main(String... strings) {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(BeanDemoConfig.class);
        System.out.println("Spring container started and is ready"); . }}Copy the code

Methods like the previous two new ***ApplicationContext are rarely used for direct production development. These are things that we use ourselves in demos or unit tests.

  1. WebApplicationContext SpringMVC

This is actually the most common way to initialize things. The ServletContext in Spring MVC provides the hosting environment for Spring’s IoC container. Is created by ContextLoaderListener initialization.

Initialization of WebApplicationContext call link: ContextLoaderListener.contextInitialized –> ContextLoader.initWebApplicationContext –> ContextLoader.createWebApplicationContext –> ContextLoader.determineContextClass –> ContextLoader determineContextClass.

The underlying layer is instantiated by reflection.

	protected WebApplicationContext createWebApplicationContext(ServletContext sc) { Class<? > contextClass = determineContextClass(sc);if(! ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
					"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
		}
		return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
	}
Copy the code

As a quick note, this is part of SpringMVC, not the Spring IoC module we are going to talk about today.

Container initializes source code parsing

Now let’s begin the source code interpretation. From the classic ClassPathXmlApplicationContext context as a starting point, to describe the whole process.

Before explaining this, I thought about the key steps of initializing the entire IoC container for you, so that you can have a general context in your heart, easier to read the source code, easier to grasp the key points. Repeat a sentence, look at the source must learn to grasp the focus, induction of core classes, core methods, core steps.

Initialization ClassPathXmlApplicationContext container we roughly divided into the following steps:

  1. BeanDefinition’s Resource location

    The Resource location here is obtained by inheriting ResourceLoader, which represents a way to load resources and is an implementation of the policy pattern.

  2. Parse and load the BeanDefinition from the Resource

  3. BeanDefinition is registered in the IoC container

As mentioned earlier, instantiating this context is starting the IoC container. So we definitely want to start with its constructor.

	public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
			throws BeansException {

		super(parent);
		setConfigLocations(configLocations);
		if(refresh) { refresh(); }}Copy the code

The configLocations parameter in this case is the classpath of your XML configuration file.

setConfigLocations(configLocations); I’m not going to expand on it, it’s not complicated, but I’m just going to parse some addresses with placeholders into actual addresses.

After that, there is refresh(), the container initialization we are talking about, named refresh because after the container is started, a call to refresh() will refresh the IoC container.

Here is the sequence diagram of IoC container initialization for easy understanding.

Refresh ()

@Override
public void refresh(a) throws BeansException, IllegalStateException {
   Refresh (); refresh(); refresh()
   synchronized (this.startupShutdownMonitor) {

      // To prepare, record the startup time of the container, mark the "started" status, and process placeholders in the configuration file
      prepareRefresh();

      // The configuration file is parsed into Bean definitions and registered with the BeanFactory.
      // Of course, the Bean is not initialized yet, but the configuration information is extracted.
      BeanName -> beanDefinition -> beanDefinition -> beanDefinition
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // Set up the BeanFactory classloader, add a few BeanPostProcessors, and manually register a few special beans
      // This section will be expanded later
      prepareBeanFactory(beanFactory);

      try {
         // BeanFactoryPostProcessor
         Spring is responsible for calling the postProcessBeanFactory method after the container is initialized. 】

         // This is the extension point provided to subclasses, at which point all beans have been loaded and registered, but have not been initialized
         // Specific subclasses can add some special BeanFactoryPostProcessor implementation classes or do something at this stage
         postProcessBeanFactory(beanFactory);
         // Call the postProcessBeanFactory(Factory) method of each BeanFactoryPostProcessor implementation class
         invokeBeanFactoryPostProcessors(beanFactory);

         // Register the BeanPostProcessor implementation class. Note the difference between BeanPostProcessor and BeanFactoryPostProcessor
         / / the interface of two methods: postProcessBeforeInitialization and postProcessAfterInitialization
         // Two methods are executed before and after Bean initialization, respectively. Notice that the Bean is not initialized at this point
         registerBeanPostProcessors(beanFactory);

         // Initialize the MessageSource of the current ApplicationContext
         initMessageSource();

         // Initializes the event announcer for the current ApplicationContext
         initApplicationEventMulticaster();

         // A typical template method (hook method),
         // Specific subclasses can initialize special beans here (before initializing Singleton beans)
         onRefresh();

         // Register event listeners that implement the ApplicationListener interface. That's not what we're talking about. Go
         registerListeners();

         // Point, point, point
         // Initialize all Singleton beans
         // (except lazy-init)
         finishBeanFactoryInitialization(beanFactory);

         // Finally, the event is broadcast and the ApplicationContext initialization is complete
         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.
         // Destroy the singleton Beans that have been initialized so that some Beans don't hog resources forever
         destroyBeans();
         // Reset 'active' flag.
         cancelRefresh(ex);
         throw ex;
      }

      finally {
         // Reset common introspection caches in Spring's core, since we
         // might not ever need metadata for singleton beans anymore...resetCommonCaches(); }}}Copy the code

I will select the following from the above processes for analysis.

  1. PrepareRefresh () Prepares the container before creating it
  2. Create the BeanFactory obtainFreshBeanFactory ()
  3. PrepareBeanFactory (beanFactory) Prepares some features for the beanFactory
  4. finishBeanFactoryInitialization(beanFactory); Initialize all Singleton Beans (DI entry)

1. PrepareRefresh () Preparation before creating a container

protected void prepareRefresh(a) {
   // Record the startup time,
   // Set the active attribute to true and the closed attribute to false, both of which are AtomicBoolean types
   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
   initPropertySources();

   // Verify the XML configuration file
   getEnvironment().validateRequiredProperties();

   this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}
Copy the code

2.★ obtainFreshBeanFactory() creates the Bean container, loads and registers the Bean

IoC initialization is the most important part.

The key is the following steps,

  • Initialize the BeanFactory
  • Load the beans
  • Registered Bean
  • .

Note: After this step, the Bean is not initialized and the actual instance is not created.

Source location: AbstractApplicationContext# obtainFreshBeanFactory ()

	protected ConfigurableListableBeanFactory obtainFreshBeanFactory(a) {
        // Close the old BeanFactory (if any), create a new BeanFactory, load the Bean definition, register the Bean, and so on
		refreshBeanFactory();
        // Returns the BeanFactory created in the previous step
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (logger.isDebugEnabled()) {
			logger.debug("Bean factory for " + getDisplayName() + ":" + beanFactory);
		}
		return beanFactory;
	}
Copy the code

Source location: AbstractRefreshableApplicationContext# refreshBeanFactory ()

	protected final void refreshBeanFactory(a) throws BeansException {
        // If the ApplicationContext has already loaded the BeanFactory, destroy all beans and close the BeanFactory
        // BeanFactory can be used as a global BeanFactory
        // The current ApplicationContext has no BeanFactory!
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
            / / initialize a DefaultListableBeanFactory
			DefaultListableBeanFactory beanFactory = createBeanFactory();
            // Serialization for BeanFactory
			beanFactory.setSerializationId(getId());
            // Here are two key methods
            // Set two important properties of the BeanFactory
            // Whether Bean overrides are allowed, and whether circular references to TODO 2.1 are allowed
			customizeBeanFactory(beanFactory);
            
            // Load the BeanDefinition into the 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); }}Copy the code

When you look at this, you get a sense of the design idea that ApplicationContext inherits from BeanFactory, but it should not be understood as an implementation class of BeanFactory, But its internal hold an instantiation of the BeanFactory (DefaultListableBeanFactory). All subsequent BeanFactory-related operations are actually delegated to this instance.

2.1 customizeBeanFactory

	protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
		if (this.allowBeanDefinitionOverriding ! =null) {
			beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		if (this.allowCircularReferences ! =null) {
			beanFactory.setAllowCircularReferences(this.allowCircularReferences); }}Copy the code

BeanDefinition overwriting problems can cause developers to run into this pitfall where they define beans with the same ID or name in their configuration files. By default, AllowBeanDefinitionOverriding attribute is null (Boolean type), if repeated, in the same configuration file will be wrong, but if it is not the same in the configuration file, cover will happen.

Circular references are also well understood: A depends on B, and B depends on A. Or A depends on B, B depends on C, and C depends on A.

By default, Spring allows cyclic dependencies, but of course if you rely on B in the constructor of A, you can’t rely on A in the constructor of B.

2.2 ★ loadBeanDefinitions(beanFactory) Loads BeanDefinition

If you look at the declaration of this method,

	/**
	 * Load bean definitions into the given bean factory, typically through
	 * delegating to one or more bean definition readers.
	 * @param beanFactory the bean factory to load bean definitions into
	 * @throws BeansException if parsing of the bean definitions failed
	 * @throws IOException if loading of bean definition files failed
	 * @see org.springframework.beans.factory.support.PropertiesBeanDefinitionReader
	 * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
	 */
	protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
			throws BeansException, IOException;

Copy the code

In the ClassPathXmlApplicationContext is according to parse the XML loading way. See Javadoc’s description for loading Bean Definitions with XmlBeanDefinitionReader.

	/**
	 * Loads the bean definitions via an XmlBeanDefinitionReader.
	 * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
	 * @see #initBeanDefinitionReader
	 * @see #loadBeanDefinitions
	 */
	@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);
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

		// Allow a subclass to provide custom initialization of the reader,
		// Initializing the Reader is not important. The javadoc for this method makes sense
		initBeanDefinitionReader(beanDefinitionReader);
        // Really important step!!
        // Use Reader to load XML configuration
		loadBeanDefinitions(beanDefinitionReader);
	}

Copy the code

loadBeanDefinitions(beanDefinitionReader)

	/** * Load the bean definitions with the given XmlBeanDefinitionReader. this method is just supposed to load and/or register bean definitions. */
	protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
		Resource[] configResources = getConfigResources();
		if(configResources ! =null) {
			reader.loadBeanDefinitions(configResources);
		}
		String[] configLocations = getConfigLocations();
		if(configLocations ! =null) {
            // This branch, which uses the pathname to get the Resource, will go the same way as abovereader.loadBeanDefinitions(configLocations); }}Copy the code

AbstractBeanDefinitionReader#loadBeanDefinitions(Resource... resources)

	@Override
	public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
		Assert.notNull(resources, "Resource array must not be null");
		int counter = 0;
		for (Resource resource : resources) {
            // Iterate through the parsed XML file to load the BeanDefinition
			counter += loadBeanDefinitions(resource);
		}
		return counter;
	}
Copy the code

The following source code is not detailed, here the load is divided into two steps,

  1. One is to obtain the Document object by calling the XML parser to complete the general XML parsing.
  2. The other is to parse according to Spring’s Bean rules. Spring’s Bean rules parse this processBeanDefinitionDocumentReaderWhich contains the processing of various Spring Bean definition rules.

I think the core point here is the parsing of the Spring Bean rules. In a nutshell, it contains the rules and steps for parsing the information we configured in XML into the BeanDefinition in the container. This part is not related to the main process, I did not paste the source code analysis, will take up a lot of space, affect reading and understanding.

Since there are many ways to configure Spring beans, many ways to parse configuration information into BeanDefinition implementations, and XML is one of the less commonly used methods, the detailed source code for parsing Spring Bean rules in XML will be skipped. Those who are interested can read Inside Spring Technology or other article books.

2.3 registered Bean

Although the source code for parsing XML into BeanDefinition is not mentioned above. But the loadBeanDefinitions(Resource) above contains our key third step, registering the Bean. This part still needs to be filled out.

Notice the code that instantiated Reader earlier,

	XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

	/**
	 * Create new XmlBeanDefinitionReader for the given bean factory.
	 * @param registry the BeanFactory to load bean definitions into,
	 * in the form of a BeanDefinitionRegistry
	 */
	public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
		super(registry);
	}
Copy the code

BeanDefinitionReader gets a reference to the beanFactory, which will be used when the beanDefinition has been loaded for registration. As you can see, because BeanDefinitionRegistry interface gives BeanFactory the ability to register BeanDefinitions.

The source code that performs the action “Register Bean”, According to the above loadBeanDefinitions language is the (resource) method has been going on DefaultBeanDefinitionDocumentReader# processBeanDefinition () method,

	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.
                / / registered Bean
				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(newBeanComponentDefinition(bdHolder)); }}Copy the code

Source location BeanDefinitionReaderUtils# registerBeanDefinition ()

	/**
	 * Register the given bean definition with the given bean factory.
	 * @param definitionHolder the bean definition including name and aliases
	 * @param registry the bean factory to register with
	 * @throws BeanDefinitionStoreException if registration failed
	 */
	public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
			throws BeanDefinitionStoreException {

		// Register bean definition under primary name.
        / / register
		String beanName = definitionHolder.getBeanName();
		registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

		// Register aliases for bean name, if any.
        // If there are any aliases, register all aliases
		String[] aliases = definitionHolder.getAliases();
		if(aliases ! =null) {
			for (String alias : aliases) {
                // To fetch the Bean, convert the Alias to BeanNameregistry.registerAlias(beanName, alias); }}}Copy the code

The above registry. RegisterBeanDefinition (beanName, definitionHolder getBeanDefinition ()); .

Source location DefaultListableBeanFactory# registerBeanDefinition ()

@Override
	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); }}// Note that this is the logical code for allowing Bean overwriting
        / / remember this configuration allowBeanDefinitionOverriding
		BeanDefinition oldBeanDefinition;

        // beanDefinitionMap is a container for all BeanDefinitions
		oldBeanDefinition = this.beanDefinitionMap.get(beanName);
        
        // not null indicates a bean with a duplicate name
		if(oldBeanDefinition ! =null) {
			if(! isAllowBeanDefinitionOverriding()) {// Determine whether overwriting is allowed. Direct throwing is not allowed
				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()) {
                // Type debug log... Override user-defined beans with beans defined by the framework
				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)) {// Type debug log... Overwrite the old Bean with the new Bean
				if (this.logger.isInfoEnabled()) {
					this.logger.info("Overriding bean definition for bean '" + beanName +
							"' with a different definition: replacing [" + oldBeanDefinition +
							"] with [" + beanDefinition + "]"); }}else {
                // Type debug log... Override the old Bean with the equivalent Bean
				if (this.logger.isDebugEnabled()) {
					this.logger.debug("Overriding bean definition for bean '" + beanName +
							"' with an equivalent definition: replacing [" + oldBeanDefinition +
							"] with [" + beanDefinition + "]"); }}/ / covers
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		else {
            // Determine if any other beans have already been initialized
			if (hasBeanCreationStarted()) {
				// Cannot modify startup-time collection elements anymore (for stable iteration)
                // Check that the beanDefinitionMap concurrency control is required
				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 {
				// Still in startup registration phase
                // The most normal branch
                
                // Register to the container
				this.beanDefinitionMap.put(beanName, beanDefinition);
                // This is an ArrayList, so the names of each registered bean are stored in the order in which they are configured
				this.beanDefinitionNames.add(beanName);
                // This is a LinkedHashSet that represents a manually registered Singleton bean,
                // Note that this is the remove method, and that the Bean is not registered manually
         		// Manual refers to beans registered by calling the following methods:
         		// registerSingleton(String beanName, Object singletonObject)
         		// That's not the point, just to keep you from getting confused. Spring will later "manually" register some beans,
         		// We can also register our own beans into the container at runtime, such as "environment" and "systemProperties" beans
				this.manualSingletonNames.remove(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}

		if(oldBeanDefinition ! =null|| containsSingleton(beanName)) { resetBeanDefinition(beanName); }}Copy the code

This is just obtainFreshBeanFactory(), and the BeanFactory is instantiated.


Let me draw a dividing line here. Since the next steps of the refresh() method will be covered, I think readers would do well to go back to the refresh() overview. (If you have the IDE open and are debugging against reading, go back to the refresh() method and continue.)

3. prepareBeanFactory(beanFactory)

This method is responsible for setting the characteristics of the BeanFactory that are reflected in the code.

	/**
	 * Configure the factory's standard context characteristics,
	 * such as the context's ClassLoader and post-processors.
	 * @param beanFactory the BeanFactory to configure
	 */
	protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		// Tell the internal bean factory to use the context's class loader etc.
        // BeanFactory needs to load classes, so you need to get the classloader
        // Sets the classloader for the current ApplicationContext
		beanFactory.setBeanClassLoader(getClassLoader());
        // The Spel interpreter is not important for now
		beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
        // Register the property editor, not important for now
		beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

		// Configure the bean factory with context callbacks.
        / / add a ApplicationContextAwareProcessor, mainly for Aware the Bean of the interface was realized
        // Extend knowledge: In Spring our own beans can capture some of the objects within Spring by implementing a series of Aware interfaces such as EnvironmentAware.
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
        // Dependency resolution ignore sets which interfaces should be ignored during dependency injection
        // In plain English, the following lines mean that if a bean depends on the implementation classes of any of the following interfaces, ignore them during auassembly,
   		// Spring handles these dependencies in other ways.
		beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
		beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
		beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
		beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

		// BeanFactory interface not registered as resolvable type in a plain factory.
		// MessageSource registered (and found for autowiring) as a bean.
        /** * The following lines assign values to specific beans. If any beans depend on any of the following, the corresponding values will be injected. Here to explain the first line * ApplicationContext also inherited the ResourceLoader, ApplicationEventPublisher, MessageSource * for this a few dependencies, so can be assigned to this, Note that this is an ApplicationContext * so we don't see assignment to MessageSource. That's because MessageSource is registered as a normal bean */
		beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
		beanFactory.registerResolvableDependency(ResourceLoader.class, this);
		beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
		beanFactory.registerResolvableDependency(ApplicationContext.class, this);

		// Register early post-processor for detecting inner beans as ApplicationListeners.
        // The BeanPostProcessor is also very simple. After the bean is instantiated, if it is a subclass of ApplicationListener,
   		// This postProcessor is used to add it to the listener list
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

		// Detect a LoadTimeWeaver and prepare for weaving, if found.
        // A special bean called loadTimeWeaver is involved. AspectJ
        // That's not the point here, leave me alone
		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.
        // Spring's "smart" operations help us register useful beans by default
        // If the bean "environment" is not defined, Spring will "manually" register one
		if(! beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); }// If the "systemProperties" bean is not defined, Spring will "manually" register one
		if(! beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME,  getEnvironment().getSystemProperties()); }// If the "systemEnvironment" bean is not defined, Spring will "manually" register one
		if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
		}
	}
Copy the code

4. U finishBeanFactoryInitialization (the beanFactory) instantiate all singleton

This is responsible for initializing all Singleton Beans.

Spring completes the instantiation of all Singleton Beans at this stage.

So far, it should be said that the BeanFactory has been created, And all beans that implement the BeanFactoryPostProcessor interface have been initialized and the postProcessBeanFactory(Factory) method in them has been callback executed. And Spring has already “manually” registered some special beans, such as environment, systemProperties, etc.

All that remains is to initialize the Singleton Beans. We know that they are singleton. If lazy loading is not set, Spring will initialize all the Singleton beans next.

Source location: AbstractApplicationContext# finishBeanFactoryInitialization ()

/** * Finish the initialization of this context's bean factory, * initializing all remaining singleton beans. */
	protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
		// Initialize conversion service for this context.
        // Initialize the "conversionService" bean. This interface is used for converting between types
		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));
		}

		// Register a default embedded value resolver if no bean post-processor
		// (such as a PropertyPlaceholderConfigurer bean) registered any before:
		// at this point, primarily for resolution in annotation attribute values.
        // Just to parse the value of the annotation, nothing important
		if(! beanFactory.hasEmbeddedValueResolver()) { beanFactory.addEmbeddedValueResolver(new StringValueResolver() {
				@Override
				public String resolveStringValue(String strVal) {
					returngetEnvironment().resolvePlaceholders(strVal); }}); }// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
        // What was said earlier is not the point here
		String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false.false);
		for (String weaverAwareName : weaverAwareNames) {
            // Initialize the LoadTimeWeaverAware bean
			getBean(weaverAwareName);
		}

		// Stop using the temporary ClassLoader for type matching.
		beanFactory.setTempClassLoader(null);

		// Allow for caching all bean definition metadata, not expecting further changes.
        // Freeze all BeanDefinition metadata
        // Nothing else, because at this point Spring has already preinitialized the Singleton beans,
        // You don't want the bean definition to be parsed, loaded, and registered.
		beanFactory.freezeConfiguration();

		// Instantiate all remaining (non-lazy-init) singletons.
        // Start initializing
		beanFactory.preInstantiateSingletons();
	}
Copy the code

Source location: DefaultListableBeanFactory# preInstantiateSingletons ()

	@Override
	public void preInstantiateSingletons(a) throws BeansException {
		if (this.logger.isDebugEnabled()) {
			this.logger.debug("Pre-instantiating singletons in " + this);
		}
		
        // copy A set copy of all beannames
		List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);

		// Trigger the initialization of all non-lazy-loaded Singleton beans
		for (String beanName : beanNames) {
            // The Bean may inherit the parent relationship to get the combined RootBeanDefinition
            // This knowledge is rarely used
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            
            // Non-abstract, non-lazy-loaded singletons
			if(! bd.isAbstract() && bd.isSingleton() && ! bd.isLazyInit()) {// If you don't know about FactoryBean, read another article or Google yourself
				if (isFactoryBean(beanName)) {
                    // FactoryBean prefixes beanName with "&"
					finalFactoryBean<? > factory = (FactoryBean<? >) getBean(FACTORY_BEAN_PREFIX + beanName);boolean isEagerInit;
                    // SmartFactoryBean
					if(System.getSecurityManager() ! =null && factory instanceof SmartFactoryBean) {
						isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
							@Override
							public Boolean run(a) {
								return((SmartFactoryBean<? >) factory).isEagerInit(); } }, getAccessControlContext()); }else {
						isEagerInit = (factory instanceofSmartFactoryBean && ((SmartFactoryBean<? >) factory).isEagerInit()); }if(isEagerInit) { getBean(beanName); }}else {
                    // This is where the normal bean is initialized
                    // Call chain is very complicatedgetBean(beanName); }}}// All non-lazy-loaded SingletonBeans have been initialized

		// Trigger post-initialization callback for all applicable beans...
        / / see comments to understand, if we define the bean is realized SmartInitializingSingleton interface,
        // Get the callback here, ignore it.
		for (String beanName : beanNames) {
			Object singletonInstance = getSingleton(beanName);
			if (singletonInstance instanceof SmartInitializingSingleton) {
				final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
				if(System.getSecurityManager() ! =null) {
					AccessController.doPrivileged(new PrivilegedAction<Object>() {
						@Override
						public Object run(a) {
							smartSingleton.afterSingletonsInstantiated();
							return null;
						}
					}, getAccessControlContext());
				}
				else{ smartSingleton.afterSingletonsInstantiated(); }}}}Copy the code

Tips aboutlazy-init

The default behavior of the ApplicationContext implementation is to instantiate all Singleton beans ahead of time at startup. Pre-instantiation means that all singleton beans are created and configured by the ApplicationContext instance as part of the initialization process. This is usually a good thing, because any errors in configuration are immediately discovered (otherwise it could take hours or even days).

Sometimes this default treatment may not be what you want. If you do not want a Singleton bean to be instantiated early when the ApplicationContext implementation is initialized, you can set the bean to lazy instantiation. A lazy initialization bean tells the IoC container whether to instantiate at startup or when it is first used.

Note that ** if a bean is set to lazy initialization and another singleton bean that is not lazy initialized depends on it, then when the ApplicationContext instantiates the Singleton bean in advance, It must also ensure that all of the above Singleton dependent beans are pre-initialized as well, including beans that are set for deferred instantiation. ** Therefore, you should not be surprised if the Ioc container creates instances of beans set to lazy instantiation at startup, as those lazy initialized beans may have been injected into a non-lazy initialized Singleton bean somewhere in the configuration.

conclusion

Above, this article is about the initialization of the Spring IoC container.

In Spring IoC design, Bean definition resolution and Bean dependency injection are two separate processes. All the previous content is about IoC container initialization, resource location, loading, and BeanDefinition resolution and registration.

The last step, instantiating all singletons, introduces the getBean() method, which is the entry point for Spring IoC dependency injection. It is also the main content of the next section of the source code interpretation.

In addition, the above source code analysis, certainly will not be complete, just extract what I think is important.

If there are omissions, please understand and consult relevant materials to learn. If wrong, please correct!