Spring bean initialization (2) - bean instantiation
XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("/spring-code-test.xml")); // bean instantiation is triggered by getBean call TestBean bean = (TestBean) bf.getBean("testbean");
The previous section talked about the first step above, loading and parsing xml. After this step is completed, the bean definition is converted into a BeanDefinition object, and the getBean method actually instantiates the BeanDefinition information.
Let's talk about the instantiation process
// AbstractBeanFactory class public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); } 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; // First get the current bean, if you can get the bean object, // Or you can get the object returned by ObjectFactory.getObject() corresponding to the bean // ObjectFactory.getObject() is to solve the circular dependency problem of singleton, which will be described in detail later Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { // Ordinary bean, this method does not process, if it is FactoryBean, // will actually return the object returned by FactoryBean.getObject() bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { //Skip the current beanfactory if there is no bean, the parent beanfactory will be queried try { // Convert beanDefinition to RootBeanDefinition, bean creation is based on RootBeanDefinition final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); // Guarantee initialization of beans that the current bean depends on. // If the bean has not been created, start creating the bean, and actually call the getObject method in the ObjectFactory, // and then call the createBean method if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { destroySingleton (beanName); throw ex; } } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } // The prototype type does not allow circular dependencies, because it is created when used, and there is no singleton-related cache to help resolve circular dependencies 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); } else { String scopeName = mbd.getScope(); final Scope scope = this.scopes.get(scopeName); try { Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { beforePrototypeCreation (beanName); try { return createBean(beanName, mbd, args); } finally { afterPrototypeCreation (beanName); } } }); bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } } } } // Check if required type matches the type of the actual bean instance. return (T) bean; }How to solve the circular dependency problem of beans in singleton mode is actually solved by caching records. Suppose A depends on B, and B depends on A. When creating an object of A, it will first instantiate A, and then put the ObjectFactory object of A into Cache the singletonFactories , then find the properties of A and inject it into B, start the creation of B, instantiate B, put the ObjectFactory object of B into the singletonFactories , then find the dependency A, instantiate A, and enter the method getSingleton(beanNam) of the above code, At this point, the object of A in singletonFactories can be obtained . Although A has not been initialized, but the reference of A has been obtained at this time, the initialization and attribute injection of B can continue to be completed. After B is completed, the dependency injection of B and A can be continued. initialization. The code for getSingleton is as follows
protected Object getSingleton(String beanName, boolean allowEarlyReference) { // Look up from the cache of bean objects that have been created, and return if found Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { // find from earlySingletonObjects singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { // If not found, go to singletonFactories to find // The object being created will first put the ObjectFactory into the singletonFactories ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); // Add the cache to improve the efficiency of the next visit this.earlySingletonObjects.put(beanName, singletonObject); // These two caches are mutually exclusive, the above one is added, the following one is useless this.singletonFactories.remove(beanName); } } } } return (singletonObject != NULL_OBJECT ? singletonObject : null); }