Spring source code analysis -- SpringIOC

Spring source code analysis -- SpringIOC

start

In Spring, there are two configuration methods, one is xml version and the other is annotation version. They correspond to different ApplicationContext. The xml version is ClassPathXmlApplicationContext, while the annotation version is AnnotationConfigApplicationContext.

// Start an ApplicationContext with our configuration file
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml");
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

Construction parameters of ApplicationContext subclass

Let's first look at the construction method of ClassPathXmlApplicationContext

org.springframework.context.support.ClassPathXmlApplicationContext#ClassPathXmlApplicationContext(java.lang.String[], boolean, org.springframework.context.ApplicationContext)

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

		super(parent);
		/*Simply set the classpath path of the incoming configuration file to the member variable configLocations*/
		setConfigLocations(configLocations);
		if (refresh) {
			/*The core part is to create the BeanFactory, scan the configuration file, load the BeanDefinition, and create and initialize the Bean*/
			refresh();
		}
	}

Then is the construction method of AnnotationConfigApplicationContext

org.springframework.context.annotation.AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(java.lang.Class<?>...)

	public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
		this();
		/**
		 * Resolve and register the configuration class, that is, the AppConfig we configured
		 * Resolve to BeanDefinition and register it in beanDefinitionMap, a member variable of BeanFactory
		 * The BeanFactory here is DefaultListableBeanFactory
		 */
		register(componentClasses);
		/*The core part is to create the BeanFactory, scan the configuration file, load the BeanDefinition, and create and initialize the Bean*/
		refresh();
	}

It can be found that different processing is done before calling the refresh() method. The abstract method of ApplicationContext () will be called, and then the abstract method of ApplicationContext () will be called.

refresh method is the most important method in Spring
org.springframework.context.support.AbstractApplicationContext#refresh

	@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

			/**
			 * Prepare this context for refreshing.
			 * Preparation, setting startup status and recording system time (unimportant)
			 */
			prepareRefresh();

			/**
			 * Create DefaultListableBeanFactory,
			 * Scan and register BeanDefinition into BeanDefinitionMap,
			 * Return this BeanFactory
			 * be careful:
			 * 	If it is an annotated bean, the BeanDefinition map will not be registered here
			 * 	Instead, it is completed through the bean factory post processor in the invokebeanfactoryprocessors below
			 */
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			/**
			 * Set the class loader of BeanFactory, add several beanpostprocessors, and manually register several special beans
			 */
			prepareBeanFactory(beanFactory);

			try {
				// This is an extension point left for the ApplicationContext subclass, which allows post-processing of the bean factory in the subclass.
				postProcessBeanFactory(beanFactory);

				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
				// The factory processor registered as a bean in the call context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register the implementation class of BeanPostProcessor. Pay attention to the difference between BeanPostProcessor and BeanFactoryPostProcessor
				// This interface has two methods: postProcessBeforeInitialization and postProcessAfterInitialization
				// The two methods are executed before and after Bean initialization. Note that the Bean has not yet been initialized
				registerBeanPostProcessors(beanFactory);
				beanPostProcess.end();

				// Initialize the MessageSource of the current ApplicationContext and internationalize it
				initMessageSource();

				// Initialize the event broadcaster of the current ApplicationContext
				initApplicationEventMulticaster();

				// You can know from the method name that a typical template method (hook method),
				// Specific subclasses can initialize some special beans here (before initializing singleton beans)
				onRefresh();

				// Register the event listener. The listener needs to implement the ApplicationListener interface
				registerListeners();

				/**
				 * Key methods:
				 * Initialize all singleton beans
				 */
				finishBeanFactoryInitialization(beanFactory);

				// Finally, broadcast the event and the ApplicationContext is initialized
				finishRefresh();
			}

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

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

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

				// Propagate exception to caller.
				throw ex;
			}

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

There is no need to look at all the above methods. We analyze IOC and mainly look at three methods

  1. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); This is the creation of BeanFactory, parsing the configuration file and loading BeanDefinition
  2. invokeBeanFactoryPostProcessors(beanFactory); This is the callback that triggers the post processor of the Bean factory
  3. finishBeanFactoryInitialization(beanFactory); This is to instantiate and initialize all beans

Create BeanFactory and load BeanDefinition

Let's first look at the first method to be analyzed in the refresh method

			/**
			 * Create DefaultListableBeanFactory,
			 * Scan and register BeanDefinition into BeanDefinitionMap,
			 * Return this BeanFactory
			 * be careful:
			 * 	If it is an annotated bean, the BeanDefinition map will not be registered here
			 * 	Instead, it is completed through the bean factory post processor in the invokebeanfactoryprocessors below
			 */
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

BeanFactory will be created in this method. The specific type is DefaultListableBeanFactory. After the DefaultListableBeanFactory is created, the configuration file will be parsed, the BeanDefinition will be loaded and registered in the beanDefinitionMap of the DefaultListableBeanFactory

org.springframework.context.support.AbstractApplicationContext#obtainFreshBeanFactory

	protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		/* Destroy the old BeanFactory, create a new BeanFactory and scan the registered BeanDefinition */
		refreshBeanFactory();
		/* Gets and returns the created BeanFactory */
		return getBeanFactory();
	}

The above method is divided into two steps

  1. Refresh the BeanFactory, that is, destroy the old BeanFactory and create a new BeanFactory. BeanDefinition will then be loaded
  2. Get and return BeanFactory

We just need to look at the first step, because after the first step, BeanFactory has been saved in the member variable of AbstractRefreshableApplicationContext, that is, the member variable of the parent class of the current ApplicationContext implementation class, so it just returns the member variable.

org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory

	@Override
	protected final void refreshBeanFactory() throws BeansException {
		/**
		 * Check whether the current ApplicationContext already has a started BeanFactory
		 * If yes, destroy the Bean and close the BeanFactory
		 */
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			/*Create DefaultListableBeanFactory*/
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			/*Set two properties of BeanFactory: whether to allow Bean overwrite and whether to allow circular reference*/
			customizeBeanFactory(beanFactory);
			/*Load BeanDefinition into BeanFactory*/
			loadBeanDefinitions(beanFactory);
			/*Save this BeanFactory to the member variable*/
			this.beanFactory = beanFactory;
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}
  1. Destroy all bean s first and close the old factory
  2. Create DefaultListableBeanFactory
  3. Set two important properties to the DefaultListableBeanFactory: allowBeanDefinitionOverriding - whether Bean overrides are allowed, and allowCircularReferences - whether circular dependencies are allowed
  4. Load BeanDefinition

Let's look directly at the four steps, BeanDefinition loading

org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.support.DefaultListableBeanFactory)

	@Override
	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		/**
		 * Create a new XmlBeanDefinitionReader for the given BeanFactory.
		 * Create an XmlBeanDefinitionReader whose function is to parse the configuration file and load BeanDefinition
		 */
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

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

		// Allow a subclass to provide custom initialization of the reader,
		// then proceed with actually loading the bean definitions.
		initBeanDefinitionReader(beanDefinitionReader);

		/* Parse the configuration file, load and register BeanDefinition */
		loadBeanDefinitions(beanDefinitionReader);
	}
  1. Create an XmlBeanDefinitionReader. It is obvious that the xml configuration file will be parsed by him
  2. loadBeanDefinitions(beanDefinitionReader); Parse the configuration file, load and register BeanDefinition

Here's the last step
org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.xml.XmlBeanDefinitionReader)

	protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
		/**
		 * If there are already loaded resources, load the previous BeanDefinition first
		 * Generally, it is the preset BeanDefinition of the extended sub ApplicationContext
		 * It's empty here, so don't go first
		 */
		Resource[] configResources = getConfigResources();
		if (configResources != null) {
			reader.loadBeanDefinitions(configResources);
		}
		/**
		 * Here is the step of reading the configuration file into a Resource and parsing and loading the BeanDefinition,
		 * Will go to the above loadbean definitions (Resource...) method
		 */
		String[] configLocations = getConfigLocations();
		if (configLocations != null) {
			reader.loadBeanDefinitions(configLocations);
		}
	}

There are two branches here

  • If there is a loaded Resource, go to the upper branch first to load the preset configuration
  • If there is no preset Resource, go to the next step to read the configuration file into a Resource object

But in fact, after the next step, we will still go to the above method. As soon as you enter here, you will go to the next branch first, because there are no pre loaded Resource objects

org.springframework.beans.factory.support.AbstractBeanDefinitionReader#loadBeanDefinitions(java.lang.String...)

	@Override
	public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
		Assert.notNull(locations, "Location array must not be null");
		int count = 0;
		for (String location : locations) {
			/*Traverse the configuration file path and load the parsing one by one*/
			count += loadBeanDefinitions(location);
		}
		return count;
	}

Here, all configuration file paths will be traversed and the configuration file will be parsed. But we only pass in one, and usually only one, so it can be regarded as a configuration file parsing, and the loop will only go through once.

org.springframework.beans.factory.support.AbstractBeanDefinitionReader#loadBeanDefinitions(java.lang.String, java.util.Set<org.springframework.core.io.Resource>)

	public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
		ResourceLoader resourceLoader = getResourceLoader();
		...
		if (resourceLoader instanceof ResourcePatternResolver) {
			try {
				/*Read the current xml configuration file into an array of resources*/
				Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
				/*Go to the previous loadbean definitions (Resource...) Method to parse the resource into BeanDefinition*/
				int count = loadBeanDefinitions(resources);
				...
				return count;
			}
			catch (IOException ex) {
				...
			}
		}
		else {
			...
		}
	}
  1. Read the current xml configuration file into an array of resources
  2. Resolve the Resource and load the BeanDefinition. Here we will go to the method in the upper branch of the previous loadBeanDefinitions method

Let's look directly at step two

org.springframework.beans.factory.support.AbstractBeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.Resource...)

	@Override
	public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
		Assert.notNull(resources, "Resource array must not be null");
		int count = 0;
		for (Resource resource : resources) {
			/*Traverse and resolve the Resource and load the BeanDefinition*/
			count += loadBeanDefinitions(resource);
		}
		return count;
	}

Traverse the Resource and call another overloaded method of loadBeanDefinitions, that is, the branch that just came in and skipped.

org.springframework.beans.factory.xml.XmlBeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.Resource)

	@Override
	public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
		/*Encapsulate the resource as encoded resource*/
		return loadBeanDefinitions(new EncodedResource(resource));
	}

There is another overloaded method with loadbean definitions. Continue to click in

org.springframework.beans.factory.xml.XmlBeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.support.EncodedResource)

	public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
		...

		Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();

		...
		/**
		 * Get the input stream of the current configuration file and encapsulate it into InputSource
		 * And load BeanDefinitions
		 */
		try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
			InputSource inputSource = new InputSource(inputStream);
			if (encodedResource.getEncoding() != null) {
				inputSource.setEncoding(encodedResource.getEncoding());
			}
			/*The loading of BeanDefinition is really started in spring, but all doxxx methods mean to really start, and the front is all foreshadowing*/
			return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
		}
		catch (IOException ex) {
			...
		}
		finally {
			currentResources.remove(encodedResource);
			if (currentResources.isEmpty()) {
				this.resourcesCurrentlyBeingLoaded.remove();
			}
		}
	}

Here, you need to call the doLoadBeanDefinitions method to start the real BeanDefinition loading

org.springframework.beans.factory.xml.XmlBeanDefinitionReader#doLoadBeanDefinitions

	protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {

		try {
			/*Resolve to Document object*/
			Document doc = doLoadDocument(inputSource, resource);
			/*Perform resolution registration of BeanDefinition*/
			int count = registerBeanDefinitions(doc, resource);
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + count + " bean definitions from " + resource);
			}
			return count;
		}
		catch ...
	}
  1. Parse the configuration file and get the Document object
  2. Load the BeanDefinition according to the Document object

Let's look at the second step

org.springframework.beans.factory.xml.XmlBeanDefinitionReader#registerBeanDefinitions

	public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		/*Create BeanDefinitionDocumentReader object*/
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		int countBefore = getRegistry().getBeanDefinitionCount();
		/*Parse the Document and register the BeanDefinition*/
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}
  1. Create BeanDefinitionDocumentReader object
  2. Parse the Document and register the BeanDefinition

Let's look at the second step

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#registerBeanDefinitions

	@Override
	public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		this.readerContext = readerContext;
		/*Get the Element node (root) in the Document and resolve it*/
		doRegisterBeanDefinitions(doc.getDocumentElement());
	}

Get the root node and start parsing from the root node

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions

	protected void doRegisterBeanDefinitions(Element root) {
		// We can see from the name that BeanDefinitionParserDelegate must be an important class, which is responsible for parsing Bean definitions,
		// Why define a parent here? You'll see later. It's a recursive problem,
		// Because < beans / > can be defined internally, the root of this method is not necessarily the root node of xml, but also the embedded < beans / > node,
		// From the perspective of source code analysis, let's just act as the root node
		BeanDefinitionParserDelegate parent = this.delegate;
		this.delegate = createDelegate(getReaderContext(), root, parent);

		if (this.delegate.isDefaultNamespace(root)) {
			String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
			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;
				}
			}
		}

		preProcessXml(root);
		/*Resolve the current node through BeanDefinitionParserDelegate*/
		parseBeanDefinitions(root, this.delegate);
		postProcessXml(root);

		this.delegate = parent;
	}

Let's look directly at parsebean definitions (root, this. Delegate);, Others ignored

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseBeanDefinitions

	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)) {
						/*Default label*/
						parseDefaultElement(ele, delegate);
					}
					else {
						/*Custom labels*/
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			/*Custom labels*/
			delegate.parseCustomElement(root);
		}
	}

There are two situations

  • The default label resolution is the spring native label
  • The analysis of custom tags is the tags provided by other frameworks integrated with spring

Let's look at the parsing of the default tag

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseDefaultElement

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

There are four kinds of tag parsing involved here. We only look at the simplest bean tag parsing

	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		/*Resolve the current bean node as BeanDefinition and wrap it with BeanDefinitionHolder*/
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				/**
				 * The registerBeanDefinition override method of DefaultListableBeanFactory will be called
				 * Register the BeanDefinition into the member variable beanDefinitionMap of DefaultListableBeanFactory
				 * this.beanDefinitionMap.put(beanName, beanDefinition);
				 */
				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
			}
			catch (BeanDefinitionStoreException ex) {
				...
			}
			...
		}
	}

In the processBeanDefinition method, the current process is divided into two steps

  1. Resolve the current bean node as BeanDefinition and wrap it with BeanDefinitionHolder
  2. Register BeanDefinition into the member variable beanDefinitionMap of DefaultListableBeanFactory

Let's look at the first step

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionElement(org.w3c.dom.Element)

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

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionElement(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinition)

	@Nullable
	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
		String id = ele.getAttribute(ID_ATTRIBUTE);
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

		List<String> aliases = new ArrayList<>();
		// Divide the definition of name attribute according to "comma, semicolon and space" to form an alias list array,
		if (StringUtils.hasLength(nameAttr)) {
			String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			aliases.addAll(Arrays.asList(nameArr));
		}

		String beanName = id;
		// If no id is specified, the first name in the alias list is used as the beanName
		if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
			beanName = aliases.remove(0);
			...
		}

		if (containingBean == null) {
			checkNameUniqueness(beanName, aliases, ele);
		}

		// According to < bean... ></ Create a BeanDefinition according to the configuration in bean >, and then set the information in the configuration to the instance
		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
		// Here, even if the parsing of the whole < bean / > tag is completed, a BeanDefinition is formed
		if (beanDefinition != null) {
			// If neither id nor name is set, the beanName will be null at this time. Enter the following code to generate
			if (!StringUtils.hasText(beanName)) {
				try {
					if (containingBean != null) {
						beanName = BeanDefinitionReaderUtils.generateBeanName(
								beanDefinition, this.readerContext.getRegistry(), true);
					}
					else {
						beanName = this.readerContext.generateBeanName(beanDefinition);
						String beanClassName = beanDefinition.getBeanClassName();
						if (beanClassName != null &&
								beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
								!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
							aliases.add(beanClassName);
						}
					}
					...
				}
				catch (Exception ex) {
				...
				}
			}
			String[] aliasesArray = StringUtils.toStringArray(aliases);
			// Return BeanDefinitionHolder
			return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
		}

		return null;
	}

The key method here is the middle one AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); Others don't need to see. Here is the parsing of Bean tag and the loading of BeanDefinition,
Then the returned BeanDefinition is wrapped as BeanDefinitionHolder

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionElement(org.w3c.dom.Element, java.lang.String, org.springframework.beans.factory.config.BeanDefinition)

	@Nullable
	public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, @Nullable BeanDefinition containingBean) {

		...

		try {
			// Create BeanDefinition
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);

			// Set a bunch of properties of BeanDefinition, which are defined in AbstractBeanDefinition
			parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
			bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

			/**
			 * The following pile is parsing < bean ></ Bean > internal child elements,
			 * The parsed information is put into the bd attribute
			 */

			// Parse < meta / >
			parseMetaElements(ele, bd);
			// Parse < lookup method / >
			parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
			// Parse < replaced method / >
			parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
			// Parse < constructor Arg / >
			parseConstructorArgElements(ele, bd);
			// Resolve < property / >
			parsePropertyElements(ele, bd);
			// Parse < qualifier / >
			parseQualifierElements(ele, bd);

			bd.setResource(this.readerContext.getResource());
			bd.setSource(extractSource(ele));

			return bd;
		}
		catch ...

		return null;
	}

As you can see, label parsing is required here, including the attributes of the bean label itself (id, name, class, scope, lazy loading...) and other nested labels

I won't look at the details. If the parsing of bean tags continues here, BeanDefinition will be returned here, and then it will be wrapped as BeanDefinitionHolder

Then go back to the processBeanDefinition method. The second step is to register the BeanDefinition into the member variable beanDefinitionMap of DefaultListableBeanFactory

/**
 * The registerBeanDefinition override method of DefaultListableBeanFactory will be called
 * Register the BeanDefinition into the member variable beanDefinitionMap of DefaultListableBeanFactory
 * this.beanDefinitionMap.put(beanName, beanDefinition);
 */
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

org.springframework.beans.factory.support.BeanDefinitionReaderUtils#registerBeanDefinition

	public static void registerBeanDefinition(
			BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
			throws BeanDefinitionStoreException {

		// Get the beanName of the BeanDefinition
		String beanName = definitionHolder.getBeanName();
		// Register this Bean
		registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

		// If there are aliases, you should also register them all according to the aliases
		String[] aliases = definitionHolder.getAliases();
		if (aliases != null) {
			for (String alias : aliases) {
				registry.registerAlias(beanName, alias);
			}
		}
	}

Here, we will get beanName as the key and BeanDefinition as the value to register. Here are the registered aliases.

Let's look directly at Bean's registration

org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition

	@Override
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

		...
		
		/*Check whether this beanName has a registered BeanDefinition*/
		BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
		if (existingDefinition != null) {
			/*If the allow BeanDefinition override property is false, an exception is thrown*/
			if (!isAllowBeanDefinitionOverriding()) {
				throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
			}
			else if (existingDefinition.getRole() < beanDefinition.getRole()) {
				...
			}
			else if (!beanDefinition.equals(existingDefinition)) {
				...
			}
			else {
				...
			}
			/* Registering BeanDefinition is actually putting it into a map */
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		else {
			if (hasBeanCreationStarted()) {
				...
			}
			else {
				// The most normal thing is to get here.
				// Put the BeanDefinition into this map
				this.beanDefinitionMap.put(beanName, beanDefinition);
				// This is an ArrayList, so the name of each registered bean will be saved in the order of bean configuration
				this.beanDefinitionNames.add(beanName);
				removeManualSingletonName(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}
		...
	}

You can see that the method overridden by DefaultListableBeanFactory is called, this beanDefinitionMap. put(beanName, BeanDefinition); Put the BeanDefinition into the member variable beandefinitionmap, which is a Map.

Then load all the tags by analogy, and then return the created DefaultListableBeanFactory. At this time, he has reported all the beandefinitions in error, except the beans declared in the annotation mode. Because there is no xml configuration file in the AnnotationConfigApplicationContext, the parameter we pass to its constructor is the class of a configuration class. It will only load this class before the refresh method is executed and become BeanDefinition. For other beans, wait until the next step in the refresh method, invokebeanfactoryprocessors (beanfactory); Completed in the middle. This is another difference between AnnotationConfigApplicationContext and ClassPathXmlApplicationContext. In fact, their differences are limited to the stage from configuration file to BeanDefinition, and their logic is the same from BeanDefinition to Bean (that is, Bean instantiation and initialization), because they both call the methods of the parent class.

The factory processor registered as a bean in the call context

After the creation of beanfactory and the loading of BeanDefinition, return to the refresh method. Beanfactory has been returned and received as ConfigurableListableBeanFactory type. The following two steps will follow

// Set the class loader of BeanFactory, add several beanpostprocessors, and manually register several special beans
prepareBeanFactory(beanFactory);
// This is an extension point left for the ApplicationContext subclass, which allows post-processing of the bean factory in the subclass.
postProcessBeanFactory(beanFactory);

But it's not the focus of our analysis, so we don't look at it. We can go directly to the next step to trigger the callback of the registered Bean factory post processor. First, let's see what is the Bean factory post processor

@FunctionalInterface
public interface BeanFactoryPostProcessor {
	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

This is the interface of the post processor of the Bean factory. The implementation class that implements this interface is the post processor of the Bean factory. The method postProcessBeanFactory implemented by the implementation class will get a callback after the BeanFactory is created and the BeanDefinition is loaded. Run us to do some operations on BeanFactory, for example, continue to add BeanDefinition to it, or modify the information in it

Back to the refresh method, we have now reached this step in the refresh method

// The factory processor registered as a bean in the call context.
invokeBeanFactoryPostProcessors(beanFactory);

org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors

	protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
		/**
		 * The main work here is:
		 * Execute all postProcessBeanFactory methods of the implementation class of beanfactory postprocessor registered in Spring
		 *
		 * However, it will be handled first:
		 * Call the postProcessBeanDefinitionRegistry method of all implementation classes that implement BeanDefinitionRegistryPostProcessor in the container
		 * BeanDefinitionRegistryPostProcessor inherits beanfactoryprocessor
		 * Spring mybatis uses this method to scan Mapper and register as BeanDefinition
		 */
		PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

		...
	}

org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.List<org.springframework.beans.factory.config.BeanFactoryPostProcessor>)

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

		// First, execute BeanDefinitionRegistryPostProcessors, if any
		Set<String> processedBeans = new HashSet<>();

		if (beanFactory instanceof BeanDefinitionRegistry) {
			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
			List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
			/**
			 * Loop through all beanfactoryprocessors,
			 * Found to be of type BeanDefinitionRegistryPostProcessor,
			 * Then call his postProcessBeanDefinitionRegistry
			 * Pass in the BeanDefinitionRegistry object,
			 * Therefore, BeanDefinitionRegistryPostProcessor is allowed to continue to register some additional beandefinitions like the container
			 * For example, all scanned mappers are registered in spring mybatis
			 */
			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
					BeanDefinitionRegistryPostProcessor registryProcessor =
							(BeanDefinitionRegistryPostProcessor) postProcessor;
					registryProcessor.postProcessBeanDefinitionRegistry(registry);
					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.
			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);
			/* Complete the parsing and registration of the annotated version of BeanDefinition through beanfactoryprocessor */
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
			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);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
			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, beanFactory.getApplicationStartup());
				currentRegistryProcessors.clear();
			}

			// Now, execute the postProcessBeanFactory callback method of all factory postprocessors
			/* Execute beanfactoryprocessor again to complete the cglib proxy */
			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<>(orderedPostProcessorNames.size());
		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<>(nonOrderedPostProcessorNames.size());
		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();
	}

There are many methods and steps here. First, trigger the callback of the subclass of BeanDefinitionRegistryPostProcessors, and then call its postProcessBeanDefinitionRegistry method. BeanDefinitionRegistryPostProcessors also implement the beanfactoryprocessor interface, so it is also a special Bean factory postprocessor.

Then the annotated Bean is loaded and registered here

Finally, the call back of beanfactoryprocessor will be performed

Instantiate and initialize all beans

Now that the post processor callback of the Bean factory has been completed, return to the refresh method.

The next step is to register the implementation class of BeanPostProcessor, that is, Bean post-processing. The post processor of Bean factory is scoped to BeanFactory, and the post processor of Bean works on Bean.

// Register the implementation class of BeanPostProcessor. Pay attention to the difference between BeanPostProcessor and BeanFactoryPostProcessor
// This interface has two methods: postProcessBeforeInitialization and postProcessAfterInitialization
// The two methods are executed before and after Bean initialization. Note that the Bean has not yet been initialized
registerBeanPostProcessors(beanFactory);

Not here

Then internationalization

// Initialize the MessageSource of the current ApplicationContext and internationalize it
initMessageSource();

It doesn't unfold, and then

// Initialize the event broadcaster of the current ApplicationContext
initApplicationEventMulticaster();

It doesn't unfold, and then

// You can know from the method name that a typical template method (hook method),
// Specific subclasses can initialize some special beans here (before initializing singleton beans)
onRefresh();

onRrefresh method is an extension point left for subclasses. For example, in SpringBoot, this method is used to complete the manual startup of Tomcat. It is not expanded here

Register event listener

// Register the event listener. The listener needs to implement the ApplicationListener interface
registerListeners();

Let's move on to the key methods, bean instantiation and initialization

// Instantiate and initialize all bean s
finishBeanFactoryInitialization(beanFactory);

org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization

	protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
		// First, initialize the Bean named conversionService
		// The initialization action is wrapped in beanfactory getBean(...)  in
		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));
		}

		...

		// Initialize the Bean of loadtimeweaveaware type first
		// It is generally used to weave third-party modules, which are dynamically woven when the class file is loaded into the JVM,
		String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
		for (String weaverAwareName : weaverAwareNames) {
			getBean(weaverAwareName);
		}
		...

		// Start initialization
		beanFactory.preInstantiateSingletons();
	}

Let's go straight to the last step, beanfactory preInstantiateSingletons();

org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons

	@Override
	public void preInstantiateSingletons() throws BeansException {
		...
		/* Get the BeanDefinition of the previous scan registration, which is the saved beanNames */
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// Trigger the initialization of all non lazy loaded singleton beans
		for (String beanName : beanNames) {
			// Merge the configuration in the parent Bean. Note the parent in < Bean id = "" class = "" parent = "" / >
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			// Non abstract, non lazy loaded singletons. If 'abstract = true' is configured, initialization is not required
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				// Processing factorybeans
				if (isFactoryBean(beanName)) {
					// For FactoryBean, add '&' before beanName. Then call getBean, getBean
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					if (bean instanceof FactoryBean) {
						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 {
					// For ordinary beans, you can initialize them by calling the get Bean (beanname) method
					getBean(beanName);
				}
			}
		}

		...
	}

Here, first get all beannames from the member variable beanDefinitionNames of DefaultListableBeanFactory, which was registered when loading BeanDefinition. Then traverse all beannames and call the getBean method.

org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)

	@Override
	public Object getBean(String name) throws BeansException {
		return doGetBean(name, null, null, false);
	}

org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

	protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {

		// Get an "orthodox" beanName and handle two situations. One is the factorybean (with '&' in front),
		// One is the alias problem, because this method is used to get beans. If you pass in an alias, it is entirely possible
		String beanName = transformedBeanName(name);

		// Note that this is followed by the return value
		Object bean;

		/**
		 * Try to get the bean from the three cache pools of BeanFactory
		 * If it is obtained, it will return without following the creation initialization method below.
		 * Function here:
		 * 1.For the bean that has been created, call getBean to get the bean
		 * 2.Return the semi-finished product of the bean (created but uninitialized) when processing circular dependency
		 */
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			if (logger.isTraceEnabled()) {
				...
			}
			// The following method: if it is an ordinary Bean, return sharedInstance directly,
			// If it is a FactoryBean, return the instance object it created
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

		/*The first time you get bean, you will enter the else branch*/
		else {
			// If the current thread has created a bean of the prototype type of this beanName, throw an exception
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			// Check whether the BeanDefinition exists in the container
			BeanFactory parentBeanFactory = getParentBeanFactory();
			/* The parent container is not empty, and this BeanDefinition does not exist in the current container */
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				// If the Binition does not exist in the current container, try whether there is an eanDef in the parent container
				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 (!typeCheckOnly) {
				markBeanAsCreated(beanName);
			}

			try {
				StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
						.tag("beanName", name);
				if (requiredType != null) {
					beanCreation.tag("beanType", requiredType::toString);
				}
				/* When you are ready to create a bean, get the BeanDefinition first */
				RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);

				// Initialize all dependent beans first
				// Note that dependencies here refer to dependencies defined in dependencies on
				String[] dependsOn = mbd.getDependsOn();
				if (dependsOn != null) {
					for (String dep : dependsOn) {
						// Check whether there is circular dependency. The circular dependency here is different from the circular dependency we mentioned earlier. It is definitely not allowed here
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						// Register dependencies
						registerDependentBean(dep, beanName);
						try {
							// Initialize dependent items first
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}

				// Creation branch of singleton instance
				if (mbd.isSingleton()) {
					/* getSingleton This anonymous inner class ObjectFactory will be called inside to create a Bean */
					sharedInstance = getSingleton(beanName, () -> {
						try {
							/* How to really create a Bean */
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							destroySingleton(beanName);
							throw ex;
						}
					});
					/**
					 * Get the real return value:
					 * If it is putongbean, it is the sharedInstance object
					 * In case of FactoryBean:
					 * 	1.beanName With &, the FactoryBean is returned
					 * 	2.Otherwise, the Bean returned by getObject returned to FactoryBean
					 */
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}

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

				// If it is not singleton or prototype, it needs to be delegated to the corresponding implementation class
				else {
					String scopeName = mbd.getScope();
					if (!StringUtils.hasLength(scopeName)) {
						throw new IllegalStateException("No scope name defined for bean ยด" + beanName + "'");
					}
					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 ScopeNotActiveException(beanName, scopeName, ex);
					}
				}
				beanCreation.end();
			}
			catch (BeansException ex) {
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			}
		}

		// Finally, check whether the type is correct. If it is wrong, throw an exception, and if it is right, return
		if (requiredType != null && !requiredType.isInstance(bean)) {
			try {
				T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
				if (convertedBean == null) {
					throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
				}
				return convertedBean;
			}
			catch (TypeMismatchException ex) {
				if (logger.isTraceEnabled()) {
					...
				}
				throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
			}
		}
		return (T) bean;
	}

The method here is very long, but we just need to take a look at a few steps

  1. Object sharedInstance = getSingleton(beanName); First try to get from the singleton cache pool
  2. Sharedinstance = getSingleton (beanname, () - > {}) creates a singleton instance, in which getSingleton will call this anonymous inner class ObjectFactory to create a Bean
  3. createBean(beanName, mbd, args); The method of anonymous internal class ObjectFactory, which is the method to really create a Bean

Attempt to get from singleton cache pool

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String)

	@Override
	@Nullable
	public Object getSingleton(String beanName) {
		/* allowEarlyReference true means circular reference is allowed */
		return getSingleton(beanName, true);
	}

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)

	@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		/*If it is fetched from the L1 cache, it will be returned directly. It usually appears in the bean that has been fetched or one-way reference */
		Object singletonObject = this.singletonObjects.get(beanName);
		/*The Bean corresponding to the current beanName cannot be obtained and is being created (after instantiation and before initialization)*/
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				/*Fetch second level from cache first*/
				singletonObject = this.earlySingletonObjects.get(beanName);
				/*Level 2 completion cannot get & & circular reference allowed*/
				if (singletonObject == null && allowEarlyReference) {
					/*Get the ObjectFactory corresponding to the current Bean from the L3 cache */
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						/*If it is obtained, call getObject to obtain the object currently being created*/
						singletonObject = singletonFactory.getObject();
						/*Add to L2 cache*/
						this.earlySingletonObjects.put(beanName, singletonObject);
						/*Delete from the L3 cache, and get it directly from the L2 cache next time*/
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

The first time I come in here, I can't get anything, so null is returned

If it cannot be fetched from the cache pool, the bean is created

Mark the work before and after bean creation

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)

	public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
		synchronized (this.singletonObjects) {
			// Try to get from the L1 cache, but the first entry is null
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
				// Judge whether the currently instantiated bean is in the destroyed collection
				if (this.singletonsCurrentlyInDestruction) {
					throw new BeanCreationNotAllowedException(beanName,
							"Singleton bean creation not allowed while singletons of this factory are in destruction " +
							"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
				}
				if (logger.isDebugEnabled()) {
					...
				}
				/**
				 * When spring feels ready to start creating beans, it first calls beforeSingletonCreation(beanName)
				 * Judge whether the bean currently being instantiated exists in the collection being created
				 * When he needs to formally create a bean, he will record that the bean is being created (add to a set set)
				 * In fact, this collection is mainly for circular dependency services
				 */
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					/**
					 * Call the getObject method of the ObjectFactory object to create and initialize the bean
					 * It's the lamda expression outside
					 * After this step, the creation and initialization of a bean are completed
					 */
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
				catch (IllegalStateException ex) {
					...
				}
				catch (BeanCreationException ex) {
					...
				}
				finally {
					if (recordSuppressedExceptions) {
						this.suppressedExceptions = null;
					}
					/*After creation, remove beanName from the collection being created */
					afterSingletonCreation(beanName);
				}
				if (newSingleton) {
					// Add to L1 cache
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

It can be seen here that spring will add and delete tags before and after creating beans, indicating that the current bean is being created, and this tag will be deleted after creation

Addition of labels
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#beforeSingletonCreation

	protected void beforeSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}
	}

The beanName of the current bean is added to singletonsCurrentlyInCreation, which means that the bean is being created

After creation, delete the label
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#afterSingletonCreation

	protected void afterSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
			throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
		}
	}

Delete beanName from singletons currentlyincreation

Singletons currentlyincreation is actually a set set

Then the creation of the real bean works on the middle line

/**
 * Call the getObject method of the ObjectFactory object to create and initialize the bean
 * It's the lamda expression outside
 * After this step, the creation and initialization of a bean are completed
 */
singletonObject = singletonFactory.getObject();

The singletonFactory object here is an ObjectFactory type, that is, the lambda expression outside, which will call
createBean(beanName, mbd, args); Method to create a bean

The lifecycle of a bean

Let's start to analyze the instantiation and initialization of beans, that is, the life cycle of beans. Of course, the loading of BeanDefinition can also be included in the life cycle of beans

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])

	@Override
	protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		...
		RootBeanDefinition mbdToUse = mbd;

		/* Get the Class object of the bean through BeanDefinition */
		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
			mbdToUse = new RootBeanDefinition(mbd);
			mbdToUse.setBeanClass(resolvedClass);
		}

		// Preparing method overrides involves another concept: MethodOverrides, which comes from < lookup method / > and < replaced method / > in the bean definition
		try {
			mbdToUse.prepareMethodOverrides();
		}
		catch (BeanDefinitionValidationException ex) {
			...
		}

		try {
			// Let the BeanPostProcessor have the opportunity to return the proxy instead of the bean instance, InstantiationAwareBeanPostProcessor
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) { // If the proxy is returned, the following creation process will not be followed
				return bean;
			}
		}
		catch (Throwable ex) {
			...
		}

		try { 
			/* The above Class object has been saved to mbdToUse to create a bean */
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			...
			return beanInstance;
		}
		catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
			...
		}
		catch (Throwable ex) {
			...
		}
	}

Let's look directly at the doCreateBean method

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean

	protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		// Instantiate bean
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			// Instantiating beans is very important here
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}

		// Interface involved: MergedBeanDefinitionPostProcessor, which allows post processors to modify the merged bean definition
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					...
				}
				mbd.postProcessed = true;
			}
		}

		/**
		 * createBeanInstance(beanName, mbd, args)After instantiation, before initialization
		 * Judge whether circular reference is supported and whether the singleton & & supports circular reference & & is being created (beanName is in singletons currentlyincreation)
		 * this.allowCircularReferences The default is true
		 * In order to solve the circular reference, a factory is cached to store the single instance after instantiation and before initialization
		 * org.springframework.beans.factory.ObjectFactory<T>
		 *     T getObject()
		 */
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			...
			/*Store the factory corresponding to the current bean in the L2 cache*/
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance
		Object exposedObject = bean;
		try {
			// This step is also very critical. This step is responsible for attribute assembly, because the previous instance is only instantiated and has no set value. Here is the set value
			// And the method marked with @ PostConstruct will also be called here, which belongs to the initialization callback
			populateBean(beanName, mbd, instanceWrapper);
			/**
			 * Execute various initialization callbacks. If the tag has init method attribute, execute the method pointed to by init method
			 * Implements the afterpropertieset() method of the InitializingBean interface
			 * Execute two callback methods (before & after) of various BeanPostProcessor implementation classes
			 */
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
			...
		}

		/**
		 * Circular reference is also involved here:
		 * At this time, the bean has been instantiated and two callback methods of beanpostprocessor have been executed,
		 * It is possible that the type of the Bean has changed, that is, it is inconsistent with the type when it is instantiated,
		 * Because the circular reference is exposed in advance after the bean is instantiated and before initialization, so that other beans can reference it
		 * At this time, the initialization of the bean is completed. If the types are inconsistent, and it is detected that other created beans depend on this bean, an error will be reported
		 */
		if (earlySingletonExposure) {
			// Try to get the singleton from the cache. Note that the following parameter is false, which means that it is not obtained from the third level cache singletonFactories. Why? Because circular dependencies are not allowed here
			Object earlySingletonReference = getSingleton(beanName, false);
			//If it is not null, it will enter the if condition, because earlySingletonReference is not null, indicating that there is a circular reference,
			//Why? Because in the first processing, the reference will be put into the singletonFactories cache. When cyclic dependency injection,
			//The pre exposed references will be obtained from singleton factories and put into the second level cache earlySingletonObjects.
			//Therefore, we get the earlySingletonReference here, indicating that there is a circular reference.
			if (earlySingletonReference != null) {
				//If they are equal, then do nothing and return the earlySingletonReference
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				/**
				 * The following is the handling of type inequality
				 * Unequal types & & there are already created beans that depend on this bean
				 * If these two conditions are met, an error will be reported
				 */
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

		// Register bean as disposable.
		try {
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}

		return exposedObject;
	}

Here is the processing of circular dependency. Let's ignore it first. We only care about the process of Bean's life cycle. There are not many important steps, but there are many comments

  1. instanceWrapper = createBeanInstance(beanName, mbd, args); Instantiate bean
  2. populateBean(beanName, mbd, instanceWrapper); Attribute injection, also known as DI
  3. exposedObject = initializeBean(beanName, exposedObject, mbd); Initialization callback of bean
bean instantiation

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance

	protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		// Make sure this class is loaded
		Class<?> beanClass = resolveBeanClass(mbd, beanName);
		// Check the access rights of this class
		if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
		}

		Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
		if (instanceSupplier != null) {
			return obtainFromSupplier(instanceSupplier, beanName);
		}

		if (mbd.getFactoryMethodName() != null) {
			/**
			 * Use static factory method to instantiate. Note that it is not FactoryBean
			 * <bean id="clientService" ="examples.ClientService" factory-method="createInstance"/>
			 */
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}

		// If it has been resolved, the function resolved constructor method is used, and there is no need to lock it again.
		// Here is through MBD Resolvedconstructorfactorymethod property to cache the resolved constructor.
		boolean resolved = false;
		boolean autowireNecessary = false;
		if (args == null) {
			synchronized (mbd.constructorArgumentLock) {
				if (mbd.resolvedConstructorOrFactoryMethod != null) {
					resolved = true;
					autowireNecessary = mbd.constructorArgumentsResolved;
				}
			}
		}
		if (resolved) {
			if (autowireNecessary) {
				// Constructor auto injection
				return autowireConstructor(beanName, mbd, null, null);
			}
			else {
				// Use default constructor construction
				return instantiateBean(beanName, mbd);
			}
		}

		// Use SmartInstantiationAwareBeanPostProcessor to parse the constructor
		// SmartInstantiationAwareBeanPostProcessor is an interface
		// The specific implementation class is AutowiredAnnotationBeanPostProcessor
		// Resolve the constructor according to the parameters and cache the resolved constructor into the resolvedconstructororfactorymode property of mdb
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
			return autowireConstructor(beanName, mbd, ctors, args);
		}

		// Preferred constructors for default construction?
		ctors = mbd.getPreferredConstructors();
		if (ctors != null) {
			// Constructor auto injection
			return autowireConstructor(beanName, mbd, ctors, null);
		}

		// No special handling: simply use no-arg constructor.
		// Use default constructor construction
		return instantiateBean(beanName, mbd);
	}

Let's look at the handling of the default constructor

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#instantiateBean

	protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
		try {
			Object beanInstance;
			if (System.getSecurityManager() != null) {
				...
			}
			else {
				beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this); // instantiation 
			}
			BeanWrapper bw = new BeanWrapperImpl(beanInstance); // Packaged as BeanWrapper
			initBeanWrapper(bw);
			return bw;
		}
		catch (Throwable ex) {
			...
		}
	}

org.springframework.beans.factory.support.SimpleInstantiationStrategy#instantiate(org.springframework.beans.factory.support.RootBeanDefinition, java.lang.String, org.springframework.beans.factory.BeanFactory)

	@Override
	public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
		// If there is no method override, use java reflection for instantiation, otherwise use CGLIB,
		// Lookup method and replaced method
		if (!bd.hasMethodOverrides()) {
			Constructor<?> constructorToUse;
			synchronized (bd.constructorArgumentLock) {
				constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
				if (constructorToUse == null) {
					final Class<?> clazz = bd.getBeanClass();
					if (clazz.isInterface()) {
						throw new BeanInstantiationException(clazz, "Specified class is an interface");
					}
					try {
						if (System.getSecurityManager() != null) {
							constructorToUse = AccessController.doPrivileged(
									(PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
						}
						else {
							constructorToUse = clazz.getDeclaredConstructor();
						}
						bd.resolvedConstructorOrFactoryMethod = constructorToUse;
					}
					catch (Throwable ex) {
						throw new BeanInstantiationException(clazz, "No default constructor found", ex);
					}
				}
			}
			// Instantiation using construction method
			return BeanUtils.instantiateClass(constructorToUse);
		}
		else {
			// There is method override, and CGLIB is used to complete instantiation, which needs to rely on CGLIB to generate subclasses
			return instantiateWithMethodInjection(bd, beanName, owner);
		}
	}

BeanUtils.instantiateClass(constructorToUse); Inside is the process of reflecting the instance through the constructor, and then returning the instantiated object. Outside, it is wrapped as a BeanWrapper object

Attribute injection

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean

	protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
		if (bw == null) {
			if (mbd.hasPropertyValues()) {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
			}
			else {
				// Skip property population phase for null instance.
				return;
			}
		}

		// At this step, the bean instantiation is completed (through the factory method or constructor method), but the property setting has not been started,
		// The implementation class of instantiaawarebeanpostprocessor can modify the state of beans here
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
				// Call the postprocessafterinstance method of the instantiaawarebeanpostprocessor implementation class
				if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
					// If false is returned, it means that there is no need to set subsequent property values or go through other BeanPostProcessor processing
					return;
				}
			}
		}

		// All the properties of the bean instance are here
		PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

		int resolvedAutowireMode = mbd.getResolvedAutowireMode();
		// If the auto assembly type is 1-byName or 2-byType, enter this branch, but this is in the form of label, not annotation @ Autowire
		if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
			// 1-AUTOWIRE_BY_NAME finds all attribute values by name. If it is a bean dependency, initialize the dependent bean first. Record dependencies
			if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
				autowireByName(beanName, mbd, bw, newPvs);
			}
			// 2-AUTOWIRE_BY_TYPE is assembled by type. More complicated
			if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
				autowireByType(beanName, mbd, bw, newPvs);
			}
			pvs = newPvs;
		}

		boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
		boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

		/* Complete the automatic assembly of annotation version through BeanPostProcessor  */
		PropertyDescriptor[] filteredPds = null;
		if (hasInstAwareBpps) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
			for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
				PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
				if (pvsToUse == null) {
					if (filteredPds == null) {
						filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
					}
					// There is a very useful BeanPostProcessor here: Autowired annotation BeanPostProcessor
					// Set the Value of dependencies annotated with @ Autowired and @ Value. The content here is also very rich
					pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						return;
					}
				}
				pvs = pvsToUse;
			}
		}
		if (needsDepCheck) {
			if (filteredPds == null) {
				filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
			}
			checkDependencies(beanName, mbd, filteredPds, pvs);
		}

		if (pvs != null) {
			// Set the property value of the bean instance
			applyPropertyValues(beanName, mbd, bw, pvs);
		}
	}

Here is the attribute injection processing of bean s in label version and attribute injection processing in annotation version
Automatic assembly types are involved here. You can first see which types are available

org.springframework.beans.factory.config.AutowireCapableBeanFactory

	/**
	 * Manual assembly
	 */
	int AUTOWIRE_NO = 0;

	/**
	 * Auto assemble by name
	 */
	int AUTOWIRE_BY_NAME = 1;

	/**
	 * Auto status by type
	 */
	int AUTOWIRE_BY_TYPE = 2;

	/**
	 * Automatic assembly by constructor
	 */
	int AUTOWIRE_CONSTRUCTOR = 3;

	/**
	 * @autowired Automatic assembly type
	 */
	@Deprecated
	int AUTOWIRE_AUTODETECT = 4;

Let's take a look at the processing of the autowireByName method, that is, automatic assembly through beanName

	protected void autowireByName(
			String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

		String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
		for (String propertyName : propertyNames) {
			if (containsBean(propertyName)) {
				/**
				 * Attribute injection, getBean gets the dependent Bean, maybe not, and needs to be created
				 * It may have been created and obtained directly from the first level cache singleObjects,
				 * Or it involves circular reference, which is obtained from the three-level cache singletonfactories
				 */
				Object bean = getBean(propertyName);
				pvs.add(propertyName, bean);
				registerDependentBean(propertyName, beanName);
				if (logger.isTraceEnabled()) {
					...
				}
			}
			else {
				if (logger.isTraceEnabled()) {
					...
				}
			}
		}
	}

You can see that if another bean is referenced in the attribute, the getBean method will be called here to create the bean, which involves circular dependency. I won't look at it here first

Initialize callback

After the property injection is completed, you need to enter the initialization callback of the bean

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)

	protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
			// If the bean implements the BeanNameAware, BeanClassLoaderAware or beanfactory aware interfaces, the callback
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			// postProcessBeforeInitialization callback of BeanPostProcessor
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			// Handle the init method defined in the bean,
			// Or if the bean implements the InitializingBean interface, call the afterpropertieset () method
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		if (mbd == null || !mbd.isSynthetic()) {
			/**
			 * BeanPostProcessor postProcessAfterInitialization callback for
			 * Aop Right here
			 */
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

You can clearly see the callback process

  1. If the bean implements the BeanNameAware, BeanClassLoaderAware or beanfactory aware interfaces, the callback
    If the bean implements the BeanNameAware interface, call back the setBeanName(String name) method; If the BeanClassLoaderAware interface is implemented, call back setBeanClassLoader(ClassLoader classLoader) method; If the BeanFactoryAware interface is implemented, the setBeanFactory(BeanFactory beanFactory) method will be called back
  2. postProcessBeforeInitialization callback of the implementation class of BeanPostProcessor (that is, Bean post processor)
  3. Process the init method defined in the bean, or call the afterpropertieset () method if the bean implements the InitializingBean interface
  4. Implementation class of BeanPostProcessor postProcessAfterInitialization callback

However, it should be noted that the method of @ PostConstruct annotation is not called back here, but in the step of attribute injection

At this point, the instantiation and initialization of a bean are completed, and the bean enters a usable state

bean destruction

At the end of each bean, there will be a step of destruction, which is the last stage of its life cycle

// If all beans are destroyed and the beans that implement the DisposableBean interface, the callback rewrites the method destroy()
// The callback specified in the xml destroy bean is also executed
// And the method of @ PreDestroy annotation in bean
destroyBeans();

Tags: Java Spring ioc bean

Posted by aksival on Sun, 22 May 2022 12:19:47 +0300