Spring source code analysis - bean loading

Let's first look at a question that is often asked in interviews: When is spring's bean instantiated?  - First: If you use BeanFactory, such as XmlBeanFactory as the factory class of Spring Bean, all beans are first Instantiated when the bean is used. Second: If you use ApplicationContext as the factory class of Spring Bean, it is divided into the following situations: 

       1. If the scope of the bean is singleton, and lazy-init is false (the default is false, so you don't need to set it), the bean is instantiated when the ApplicationContext starts, and the instantiated bean is placed in a thread-safe In the cache of the ConcurrentHashMap structure, the next time the bean is used, it is directly taken from the cache.

        2. If the scope of the bean is singleton and lazy-init is true, the instantiation of the bean is instantiated when the bean is used for the first time.

       3. If the scope of the bean is prototype, the instantiation of the bean is instantiated when the bean is used for the first time.

ClassPathXmlApplicationContext has several overloaded constructors that will eventually call the reflash method of the parent class AbstractApplicationContext. The reflash method was introduced in the previous section, and its function is to create and load the Spring container configuration. AbstractApplicationContext also has a getBean method:

AbstractApplicationContext下的代码:
public Object getBean(String name)throws BeansException {
        //Bean的获取外部容器交给了内部容器
        return getBeanFactory().getBean(name);
}

The inner container is undertaken by DefaultListableBeanFactory, but the real getBean method is implemented by its parent class AbstractBeanFactory. The AbstractBeanFactory class also implements the methods of the BeanFactory interface. It has four overloaded getBean methods, no matter which one will call the doGetBean method:

                

                

So what's going on in doGetBean?

protected <T> T doGetBean(
			final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)throws BeansException { 
//bean name处理,去除FactoryBean前缀等  
     final String beanName = transformedBeanName(name);  
     Object bean = null;  
  
//先从singleton缓存中查看是否已经实例化过该Bean,根据是否有缓存分为两个分支分别处理  
    Object sharedInstance = getSingleton(beanName);  
    if (sharedInstance != null && args == null) {  
// 分支一,若缓存中获取到了并且该BeanDefinition信息表明该bean是singleton的,直接将获取到的缓存Bean  
//(有可能是半成品)交给getObjectForBeanInstance处理  
 /*.........省略logger部分代码............*/  
//调用getObjectForBeanInstance处理  
     bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);  
    }else {  
// 分之二:没有缓存,则需要从头实例化该bean  
            // We're assumably within a circular reference.  
      if (isPrototypeCurrentlyInCreation(beanName)) {   
           throw new BeanCurrentlyInCreationException(beanName);}  
  
// 检查BeanDefinition是否在当前工厂或父工厂  
            BeanFactory parentBeanFactory = getParentBeanFactory();  
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {  
                // Not found -> check parent.  
                String nameToLookup = originalBeanName(name);  
                if (args != null) {  
// 父工厂getBean  
                    return parentBeanFactory.getBean(nameToLookup, args);  
                }  
                else {  
                    // No args -> delegate to standard getBean method.  
                    return parentBeanFactory.getBean(nameToLookup, requiredType);  
                }  
            }  
//将bean加入“正在创建”的集合,完成后会remove,对应afterSingletonCreation/afterPrototypeCreation方法  
            if (!typeCheckOnly) {  
                markBeanAsCreated(beanName);  
            }  
  
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);  
            checkMergedBeanDefinition(mbd, beanName, args);  
  
// 解决依赖关系,将依赖的bean提前实例化  
            String[] dependsOn = mbd.getDependsOn();  
            if (dependsOn != null) {  
                for (int i = 0; i < dependsOn.length; i++) {  
                    String dependsOnBean = dependsOn[i];  
                    getBean(dependsOnBean);  
                    registerDependentBean(dependsOnBean, beanName);  
                }  
            }  
  
// 这里又需要根据bean的类型分为三种情况:singleton、prototype、request/session  
            if (mbd.isSingleton()) {  
                           //通过自定义ObjectFactory实例化Bean,此结果可能是半成品(是FactoryBean等)  
                sharedInstance = getSingleton(beanName, new ObjectFactory() {  
                    public Object getObject()throws BeansException {  
                        try {  
                          //真正实例化装配的逻辑在createBean方法中  
                            return createBean(beanName, mbd, args);  
                        }  
                        catch (BeansException ex) {   
                            destroySingleton(beanName);  
                            throw ex;  
                        }  
                    }  
                });  
                        //上一步半成品的Bean交给getObjectForBeanInstance方法处理  
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);  
            }  
  
            else if (mbd.isPrototype()) {  
                Object prototypeInstance = null;  
                try {  
                    beforePrototypeCreation(beanName);  
                     //真正实例化装配的逻辑在createBean方法中  
                    prototypeInstance = createBean(beanName, mbd, args);  
                }  
                finally {  
                    afterPrototypeCreation(beanName);  
                }  
                    //上一步半成品的Bean交给getObjectForBeanInstance方法处理  
               bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);  
            }  
  
            else {  
                            //request、session 的bean  
                String scopeName = mbd.getScope();  
                final Scope scope = (Scope) this.scopes.get(scopeName);  
                if (scope == null) {  
        throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");  
                }  
                try {  
                    Object scopedInstance = scope.get(beanName, new ObjectFactory() {  
                        public Object getObject()throws BeansException {  
                            beforePrototypeCreation(beanName);  
                            try {  
                         //真正实例化装配的逻辑在createBean方法中  
                                return createBean(beanName, mbd, args);  
                            }  
                            finally {  
                                afterPrototypeCreation(beanName);  
                            }  
                        }  
                    });  
                       //上一步半成品的Bean交给getObjectForBeanInstance方法处理  
                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);  
                }  
            }  
        }  
   
        if (requiredType != null && bean != null &&  
                              !requiredType.isAssignableFrom(bean.getClass())) {  
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());  
        }  
        return bean;  
    }  

    The loading of beans has gone through a complex process. The above code mainly does the following things (this paragraph is excerpted from "Spring Source Code Deep Analysis" ):

        1. Convert the corresponding beanName. If name="&aa", the ampersand will be removed. Or <bean> tag with alias (alias meaning), then take the final beanName represented by alias.

         2. Attempt to load singleton bean from cache. If the load is unsuccessful, it will try to load from the singletonFactories again.

        3. Bean instantiation. If we need to process the factory bean, what we get here is the initial state of the factory bean. The real work is getObjectForBeanInstance defines the bean returned by the factory-method method.

        4. Prototype pattern dependency checking. If class A has the properties of B, and B has the properties of A, there will be a circular dependency. How does spring solve the circular dependency problem

        5. Convert the GernericBeanDefinition of the stored Xml configuration file to the RootBeanDefinition. There are three implementations of the BeanDefinition used to carry properties mentioned above, GernericBeanDefinition, RootBeanDefinition and ChildBeanDefinition. If the parent class bean is not empty, all the properties will be combined with the parent class properties, because all subsequent beans are for RootBeanDefinition.

        6. Find dependencies. When a bean is initialized, the dependencies corresponding to the bean are initialized first.

        7. Create beans according to different scopes. The scope attribute defaults to singleton, as well as prototype, request, etc.

        8. Type conversion. If the bean is a String, and the requiredType is passed in Integer, then the bean is returned, and the loading is over.

Among them, the most important step is (7), where the common features of spring are implemented.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326548800&siteId=291194637