Without further ado, let’s do a dumb-ass IOC demo as an example

Custom Bean definitions

class MyBeanDefinition{ public String id; public String className; public String value; public MyBeanDefinition(String id, String className, String value) { this.id = id; this.className = className; this.value = value; }}Copy the code

Custom Bean factories

class MyBeanFactory { Map<String, Object> beanMap = new HashMap<>(); public MyBeanFactory(MyBeanDefinition beanDefinition) throws ClassNotFoundException, IllegalAccessException, InstantiationException { Class<? > beanClass = Class.forName(beanDefinition.className); Object bean = beanClass.newInstance(); ((UserService) bean).setName(beanDefinition.value); beanMap.put(beanDefinition.id, bean); } public Object getBean(String id) {returnbeanMap.get(id); }}Copy the code

Test the foolproof IOC container

public class EasyIOC {

    public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException {

        MyBeanDefinition beanDefinition = new MyBeanDefinition("userService"."com.valarchie.UserService"."archie");

        MyBeanFactory beanFactory = new MyBeanFactory(beanDefinition);
        UserService userService = (UserService) beanFactory.getBean("userService"); System.out.println(userService.getName()); }}Copy the code

So what can we think about after we look at this stupid example? What is the key to enabling ourselves to implement IOC containers?

As I understand it, I summarize it as the following three steps

  • Read the XML file to form a DOM object
  • Read the Bean definition from the DOM document object and load it into the BeanFactory
  • Generate an instance from the bean definition to put into the container for use

Therefore, next we will not analyze the whole IOC process, because there are too many details on the side of the reader will not grasp the key point in the fog. We understand the IOC process by analyzing the most important code backbone.

Start analyzing:

Let’s start with XML configuration, which most people are familiar with and easy to understand because Spring’s original configuration method is XML configuration.

To start from the ClassPathXmlApplicationContext constructor.

Public class TestSpring {public static void main (String [] args) {/ / IOC container start from ClassPathXmlApplicationContext constructor ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml");
        UserService userService = (UserService) context.getBean("userService"); System.out.println(userService.getName()); }}Copy the code

Go into the constructor and call another constructor that is overloaded.

/ / create a ClassPathXmlApplicationContext, loading given the location of the XML file, Automatically refresh the context and public ClassPathXmlApplicationContext (String configLocation) throws BeansException {this (new String [] {configLocation},true, null);
}
Copy the code

The overloaded constructor does not set the parent container because the parrent argument was passed null. Refresh has just been set to true, and the process enters the refresh() method

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {// Since the previous method call set parent to null, we do not parse super(parent); // Set the path array, and then perform simple placeholder substitution for the configuration pathsetConfigLocations(configLocations);
		if(refresh) { refresh(); }}Copy the code

The whole refresh() method is the backbone of the IOC container startup. Spring uses the template method design pattern to design the Refresh () method, specifying the steps of the entire IOC container, and then implementing each small step by the various subclasses themselves.

All the important operations are going on around the BeanFactory. In the comments, we list in detail what each step of the method does. ApplicationContext holds an instance of a FactoryBean internally. The topmost parent interface of the ApplicationContext itself is also BeanFactory, which extends the functions of BeanFactory (providing internationalized message access, resource access such as URLS and files, event propagation, loading multiple (inherited) contexts).

Let’s start by reading comments in the code to get a sense of the context.

public void refresh() throws BeansException, An IllegalStateException {/ / lock to prevent the start and end the conflict first synchronized (enclosing startupShutdownMonitor) {/ / do some preparation work before the refresh / / Set the startup time, flag bits for the associated state (active, off), initialize the placeholder property source, and verify that // each property marked as required is resolvable. prepareRefresh(); // Get a refreshed BeanFactory instance. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Define the Bean factory environment properties, such as the classloader, or prepareBeanFactory(beanFactory); Try {// Set some post-operations after the BeanFactory has finished initialization, which Spring leaves to the extension of subclasses. postProcessBeanFactory(beanFactory); / / start has been set before the BeanFactory post processor invokeBeanFactoryPostProcessors (the BeanFactory); / / registered Bean processors registerBeanPostProcessors (the beanFactory); // Set the message source (i18n) initMessageSource() for our application context; / / initialize event broadcast initApplicationEventMulticaster (); // Initialize the special Bean in the special Context, the default implementation is null, give each concrete subclass to implement onRefresh(); // Check listeners and register registerListeners(); / / instantiate all the lazy loading of Bean finishBeanFactoryInitialization (the beanFactory); // The final step is to publish the corresponding event finishRefresh(); } catch (BeansException ex) {if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: "+ ex); } // If the startup fails, destroy the previously created Beans. destroyBeans(); CancelRefresh (ex); // Reset the active flag bit in ApplicationContext. // Throw the exception throw ex to the caller; } finally {// Reset the cache in the Spring core, since we may no longer need the singleton bean-related metadata resetCommonCaches(); }}}Copy the code

After reading, we focus on obtainFreshBeanFactory (), finishBeanFactoryInitialization (the beanFactory) these two methods, because virtually the entire process of IOC in these two methods, The other methods are part of the custom operations Spring reserves for users such as the BeanFactory post-handler and Bean post-handler, part of the publishing and listening operations for key start events, and part of the AOP operations.

Start with obtainFreshBeanFactory().

Step 1: Read the XML file to form a DOM object

The refreshBeanFactory() method is called before the getBeanFactory() method. To clarify, getBeanFactory() is very simple, and the default implementation simply returns the Bean factory built after the previous flush succeeded. The returned Bean factory has loaded the Bean definition. So the refreshBeanFactory() method already contains the first step of reading the XML file to build the DOM object and the second step of parsing the elements in the DOM to generate the Bean definition for saving. Remember, this is just saving the Bean definition; there is no instantiation of the Bean at this point.

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		refreshBeanFactory();
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (logger.isDebugEnabled()) {
			logger.debug("Bean factory for " + getDisplayName() + ":" + beanFactory);
		}
		return beanFactory;
}
Copy the code

Enter the refreshBeanFactory() method

Protected final void refreshBeanFactory() throws BeansException {// Destroy FactoryBean if it already exists in the current ApplicationContextif(hasBeanFactory()) { destroyBeans(); closeBeanFactory(); Mr} try {/ / into a the BeanFactory DefaultListableBeanFactory the BeanFactory = createBeanFactory (); / / set to serialize the beanFactory. SetSerializationId (getId ()); CustomizeBeanFactory (beanFactory); // Set whether the Bean definition can be overridden and whether it can loop dependencies. // Load the Bean definition into the Factory. 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

Next, enter the core method loadBeanDefinitions(beanFactory) with the beanFactory you just created

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {// Create an XML reader based on the passed beanFactory XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); / / set the bean definitions related resource loading environment beanDefinitionReader reader. SetEnvironment (enclosing getEnvironment ()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); InitBeanDefinitionReader (beanDefinitionReader); // Then start loading the Bean loadBeanDefinitions(beanDefinitionReader); }Copy the code

If you go to the loadBeanDefinitionReader (beanDefinitionReader) method, the argument is the Reader Reader you just created.

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {// If there are already generated instances of Resouce, parse directly. // The default implementation is to return null, implemented by subclasses themselves. Resource[] configResources = getConfigResources();if(configResources ! = null) { reader.loadBeanDefinitions(configResources); } // Path resolution is performed without Resouces. String[] configLocations = getConfigLocations();if (configLocations != null) {
			reader.loadBeanDefinitions(configLocations);
		}
}

Copy the code

Us into the reader. LoadBeanDefinitions (configLocations) method, this method calls a bit around inside, I simply describe here

The method processes the XML files sequentially based on multiple locations. The path is then treated differently depending on how the path is written, such as the prefix path of classpath or WEB-INF. Generate the appropriate Resouces based on the locations variables passed in. And then into the reader. LoadBeanDefinitions (resource) parameter is the resource at this time. In a method call to loadBeanDefinitions(New EncodedResource(Resource)) through one layer.

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
	Assert.notNull(encodedResource, "EncodedResource must not be null");
	if (logger.isInfoEnabled()) {
		logger.info("Loading XML bean definitions from "+ encodedResource.getResource()); } / / the current currentResource Set by ThreadLocal < EncodedResource > currentResources = this. ResourcesCurrentlyBeingLoaded. The get ();if (currentResources == null) {
		currentResources = new HashSet<EncodedResource>(4);
		this.resourcesCurrentlyBeingLoaded.set(currentResources);
	}
	if(! currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!"); } the try {/ / the main methods in this period of InputStream InputStream. = encodedResource getResource () getInputStream (); InputSource = new InputSource(inputStream);if(encodedResource.getEncoding() ! = null) { inputSource.setEncoding(encodedResource.getEncoding()); }return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
		}
		finally {
			inputStream.close();
		}
	}
	catch (IOException ex) {
		throw new BeanDefinitionStoreException(
				"IOException parsing XML document from " + encodedResource.getResource(), ex);
	}
	finally {
		currentResources.remove(encodedResource);
		if(currentResources.isEmpty()) { this.resourcesCurrentlyBeingLoaded.remove(); }}}Copy the code

This method is mainly to create the corresponding input stream, and set up the encoding.

Then you start calling the doLoadBeanDefinitions() method.

// Document doc =doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);
		
Copy the code

A DocumentBuilderImpl object is generated in the loadDocument() method, which calls the Parse method, where SAX is used to parse the InputSource wrapped by the input stream and generate the DOM object returned.

public Document parse(InputSource is) throws SAXException, IOException {
        if (is == null) {
            throw new IllegalArgumentException(
                DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
                "jaxp-null-input-source", null));
        }
        if(fSchemaValidator ! = null) {if(fSchemaValidationManager ! = null) { fSchemaValidationManager.reset(); fUnparsedEntityHandler.reset(); } resetSchemaValidator(); } // parse XML domparser. parse(is); Doc = domParser.getDocument(); domParser.dropDocumentReferences();return doc;
}
Copy the code

Now that our XML file has been loaded and parsed into DOM structured objects, the first step is complete.

Step 2: Read the Bean definition from the DOM document object and load it into the BeanFactory

// Document doc =doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);
		
Copy the code

We return to the two core lines of code that we have just described. The first line gets the DOM object, followed by the second line registerBeanDefinitions(doc, Resource) to start registering the bean definition.

Enter the registerBeanDefinitions(doc, Resource) method

Public int registerBeanDefinitions (Document, doc, the Resource the Resource) throws BeanDefinitionStoreException {/ / generates DOM reader, This is different from the previous reader, which was an XML reader. BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); Int countBefore = getRegistry().getBeandefinitionCount (); / / enter key documentReader. RegisterBeanDefinitions (doc, createReaderContext (resource)); // Number of bean definitions just created - number of previous bean definitions = total bean definitions just createdreturn getRegistry().getBeanDefinitionCount() - countBefore;
}

Copy the code

Enter documentReader. RegisterBeanDefinitions (doc, createReaderContext (resource) method. Method to read the root element of the document.

protected void doRegisterBeanDefinitions(Element root) {
		// Any nested <beans> elements will cause recursion in this method. In
		// order to propagate and preserve <beans> default-* attributes correctly,
		// keep track of the current (parent) delegate, which may be null. Create
		// the new (child) delegate with a reference to the parent for fallback purposes,
		// thenultimately reset this.delegate back to its original (parent) reference. // this behavior emulates a stack of delegates without actually necessitating one. BeanDefinitionParserDelegate parent = this.delegate; This. delegate = createDelegate(getReaderContext(), root, parent); // If it is a namespace in an XML document, handle it accordinglyif (this.delegate.isDefaultNamespace(root)) {
			String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
			if (StringUtils.hasText(profileSpec)) {
				String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
						profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
				if(! getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {if (logger.isInfoEnabled()) {
						logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
								"] not matching: " + getReaderContext().getResource());
					}
					return; // Spring reserves the extension method preProcessXml(root) for subclasses; // Start parseBeanDefinitions(root, this.delegate); // Spring reserves the extension method postProcessXml(root) for subclasses; this.delegate = parent; }Copy the code

Go to parseBeanDefinitions(root, this.delegate). Pass in the previous document object and bean definition resolution class as parameters.

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		if(delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); // Traverse to parse each child element of the root nodefor(int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); // If it is a tag elementif (node instanceof Element) {
					Element ele = (Element) node;
					if(delegate. IsDefaultNamespace (ele)) {/ / parse the default element / / key parseDefaultElement (ele, delegate); }else{/ / analytical element to specify a custom delegate. ParseCustomElement (ele); }}}}else{// Custom parsing is performed for non-default namespaces. The namespace is XMLNS in the XML document header, which is used to define tags. delegate.parseCustomElement(root); }}Copy the code

If you go to parseDefaultElement(ele, delegate), you’ll see that the four tags are parsed separately.

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			importBeanDefinitionResource(ele);
		}
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			processAliasRegistration(ele);
		}
		else if(delegate. NodeNameEquals (ele, BEAN_ELEMENT)) {processBeanDefinition(ele, delegate); }else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			// recurse
			doRegisterBeanDefinitions(ele); }}Copy the code

We’ll focus on parsing Bean element labels, going to the innermost layer of the processBeanDefinition(ele, Delegate) method.

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, String id = ele.getAttribute(ID_ATTRIBUTE); String id = ele.getAttribute(ID_ATTRIBUTE); Name String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); List<String> aliases = new ArrayList<String>();if(StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } // String beanName = id;if(! StringUtils.hasText(beanName) && ! aliases.isEmpty()) { beanName = aliases.remove(0);if (logger.isDebugEnabled()) {
				logger.debug("No XML 'id' specified - using '" + beanName +
						"' as bean name and " + aliases + " as aliases"); }} // Check whether beanName is uniqueif(containingBean == null) { checkNameUniqueness(beanName, aliases, ele); } / / internal did Bean tags analysis AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement (ele, beanName containingBean);if(beanDefinition ! = null) {if(! StringUtils.hasText(beanName)) { try {if(containingBean ! = null) { beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this.readerContext.getRegistry(),true);
					}
					else {
						beanName = this.readerContext.generateBeanName(beanDefinition);
						// Register an alias for the plain bean class name, if still possible,
						// if the generator returned the class name plus a suffix.
						// This is expected forSpring 1.2/2.0 backwards compatibility. String beanClassName = beanDefinition. GetBeanClassName ();if(beanClassName ! = null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && ! this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) { aliases.add(beanClassName); }}if (logger.isDebugEnabled()) {
						logger.debug("Neither XML 'id' nor 'name' specified - " +
								"using generated bean name [" + beanName + "]");
					}
				}
				catch (Exception ex) {
					error(ex.getMessage(), ele);
					return null;
				}
			}
			String[] aliasesArray = StringUtils.toStringArray(aliases);
			return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
		}

		return null;
}
Copy the code

Return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray) with the parsed Bean definition and append an array of aliases. Then call the following method.

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry())
Copy the code

The main operation is to put the Bean definitions you just parsed into a beanDefinitionMap.

Save the Bean definition after successful parsing. The second step has been completed.

Step 3: Using the created Bean definition, start instantiating the Bean.

We go back to the start of the refresh method, in finishBeanFactoryInitialization (the beanFactory) method, the Bean object to instantiate the lazy loading. We follow the call chain into the preInstantiateSingletons() method

@Override
public void preInstantiateSingletons() throws BeansException {
	if (this.logger.isDebugEnabled()) {
		this.logger.debug("Pre-instantiating singletons in "+ this); } List<String> beanNames = new ArrayList<String>(this.beandefinitionNames); // Triggers all non-lazy-loaded singleton Bean instantiationsfor(String beanName : beanNames) { RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); // If non-abstract and singleton and non-lazy loadingif(! bd.isAbstract() && bd.isSingleton() && ! Bd.islazyinit ()) {// Check if it is a factory method Bean. Readers can search for different ways to create beans.if(isFactoryBean(beanName)) { final FactoryBean<? > factory = (FactoryBean<? >) getBean(FACTORY_BEAN_PREFIX + beanName); boolean isEagerInit;if(System.getSecurityManager() ! = null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() { @Override public Booleanrun() {
							return((SmartFactoryBean<? >) factory).isEagerInit(); } }, getAccessControlContext()); }else{ isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<? >) factory).isEagerInit()); }if(isEagerInit) { getBean(beanName); }}else{ getBean(beanName); }}} // The code for the custom operation done after instantiation is omitted.... }Copy the code

The primary method in this method is the getBean(beanName) method, depending on whether the Bean instance is instantiated through a factory method or plain. Let’s move on to the process of common instantiation. Enter the doGetBean() method of getBean() and find that the last three parameters of method parameter doGetBean(name, NULL, NULL, false) are all null, which is the core code of the whole IOC.

In the code, the Bean is instantiated first. After instantiation, the dependency required by the Bean is determined, and the Bean is instantiated recursively. After success, the core process of the whole IOC is completed.

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

	final String beanName = transformedBeanName(name);
	Object bean;

	// Eagerly check singleton cache for manually registered singletons.
	Object sharedInstance = getSingleton(beanName);
	if(sharedInstance ! = null && args == null) {if (logger.isDebugEnabled()) {
			if (isSingletonCurrentlyInCreation(beanName)) {
				logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
						"' that is not fully initialized yet - a consequence of a circular reference");
			}
			else {
				logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
			}
		}
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}

	else{// If the current Bean is being created, it fails, and // can be trapped in a circular reference.if(isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); BeanFactory parentBeanFactory = getParentBeanFactory();if(parentBeanFactory ! = null && ! ContainsBeanDefinition (beanName)) {// If the parent factory is not null and does not currently contain the Bean definition // Return Bean String nameToLookup = from the parent factory originalBeanName(name);if(args ! = null) { // Delegation to parent with explicit args.return (T) parentBeanFactory.getBean(nameToLookup, args);
			}
			else {
				// No args -> delegate to standard getBean method.
				returnparentBeanFactory.getBean(nameToLookup, requiredType); }} // Mark as created if no type checking is requiredif (!typeCheckOnly) { markBeanAsCreated(beanName); } the try {/ / defines child Bean definition and parent Bean integrate final RootBeanDefinition MBD = getMergedLocalBeanDefinition (beanName); / / if found after integration is an abstract class cannot be an exception instance checkMergedBeanDefinition (MBD, beanName, args); String[] dependsOn = mbd.getDependson ();if(dependsOn ! = null) {for(String dep: dependsOn) {// Check whether a circular dependency existsif (isDependent(beanName, dep)) {
						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
								"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); } // Register the dependent Bean registerDependentBean(dep, beanName); // The recursive call generates the required dependent Bean getBean(deP); } catch (NoSuchBeanDefinitionException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName,"'" + beanName + "' depends on missing bean '" + dep + "'", ex); }}} // If it is a singletonif (mbd.isSingleton()) {
				sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
					@Override
					public Object getObject() throws BeansException {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// Explicitly remove instance from singleton cache: It might have been put there
							// eagerly by the creation process, to allow forcircular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; }}}); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } // If it is a prototypeelse 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); } // Non-singleton and prototype scope else {String scopeName = mbd.getScope(); final Scope scope = this.scopes.get(scopeName); if (scope == null) { throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'"); } try { Object scopedInstance = scope.get(beanName, new ObjectFactory() { @Override public Object getObject() throws BeansException { beforePrototypeCreation(beanName); try { return createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); }}}); bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } catch (IllegalStateException ex) { throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; consider " + "defining a scoped proxy for this bean if you intend to refer to it from a singleton", ex); } } } catch (BeansException ex) { cleanupAfterBeanCreationFailure(beanName); throw ex; If (requiredType! = null && bean ! = null && ! requiredType.isInstance(bean)) { try { return getTypeConverter().convertIfNecessary(bean, requiredType); } catch (TypeMismatchException ex) { if (logger.isDebugEnabled()) { logger.debug("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", ex); } throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } } return (T) bean; }Copy the code

Instantiate the Bean according to the Bean definition. The third step has been completed.

Paper length is limited, the IOC the whole creation process is lengthy, want the reader to read the article to the IOC’s creation process have a after the main context of thinking still need to open source, in fact it is not difficult to read the source code, because Spring code comments are quite perfect, if there are any unclear Google it slightly. Readers are advised to try to analyze the source code of the IOC process step by step.

My personal blog, vc2x.com