《Spring源碼深度解析》讀書筆記 - bean的加載

基本流程

完成了XML配置文件的解析,接下來就是對bean加載的探索。

//2.從ioc容器中獲取bean實例
MyTestBean myTestBean = (MyTestBean) beanFactory.getBean("myTestBean");

跟蹤進Spring的源碼

public Object getBean(String name) throws BeansException {
    return this.doGetBean(name, (Class)null, (Object[])null, false);
}

protected <T> T doGetBean(String name, Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException {
    // 1. 提取對應的beanName
    final String beanName = this.transformedBeanName(name);
    // 2. 直接嘗試從緩存獲取或者singletonFactories中的ObjectFactory中獲取
    Object sharedInstance = this.getSingleton(beanName);
    Object bean;
    if (sharedInstance != null && args == null) {
        if (this.logger.isDebugEnabled()) {
            if (this.isSingletonCurrentlyInCreation(beanName)) {
                this.logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");
            } else {
                this.logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
            }
        }
        // 3.返回對應的實例,有時候存儲諸如BeanFactory的情況並不是直接返回實例本身而是返回指定方法返回的實例
        bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
    } else {
        // 4.
        if (this.isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }

        BeanFactory parentBeanFactory = this.getParentBeanFactory();
        // 5.如果beanDefinitionMap中也就是在所有已經加載的類中不包括beanName,則嘗試從parentBeanFactory中檢測
        if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {
            String nameToLookup = this.originalBeanName(name);
            // 遞歸到BeanFactory中尋找
            if (args != null) {
                return parentBeanFactory.getBean(nameToLookup, args);
            }

            return parentBeanFactory.getBean(nameToLookup, requiredType);
        }
        // 如果不是僅僅做類型檢查則是創建bean,這裏要進行記錄
        if (!typeCheckOnly) {
            this.markBeanAsCreated(beanName);
        }

        try {
            // 6.將存儲XML配置文件的GernericBeanDefinition轉換爲RootBeanDefinition,如果指定BeanName是子Bean的話同時會合並父類的相關屬性
            final RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
            this.checkMergedBeanDefinition(mbd, beanName, args);
            String[] dependsOn = mbd.getDependsOn();
            String[] var11;
            // 7.若存在依賴則需要遞歸實例化依賴的bean
            if (dependsOn != null) {
                var11 = dependsOn;
                int var12 = dependsOn.length;

                for(int var13 = 0; var13 < var12; ++var13) {
                    String dep = var11[var13];
                    if (this.isDependent(beanName, dep)) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                    }
                    // 緩存依賴調用
                    this.registerDependentBean(dep, beanName);
                    this.getBean(dep);
                }
            }
            // 8.singleton模式的創建
            if (mbd.isSingleton()) {
                sharedInstance = this.getSingleton(beanName, new ObjectFactory<Object>() {
                    public Object getObject() throws BeansException {
                        try {
                            return AbstractBeanFactory.this.createBean(beanName, mbd, args);
                        } catch (BeansException var2) {
                            AbstractBeanFactory.this.destroySingleton(beanName);
                            throw var2;
                        }
                    }
                });
                bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            } else if (mbd.isPrototype()) {
                // prototype模式的創建
                var11 = null;

                Object prototypeInstance;
                try {
                    this.beforePrototypeCreation(beanName);
                    prototypeInstance = this.createBean(beanName, mbd, args);
                } finally {
                    this.afterPrototypeCreation(beanName);
                }

                bean = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            } else {
                // 指定的scope是實例化bean
                String scopeName = mbd.getScope();
                Scope 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<Object>() {
                        public Object getObject() throws BeansException {
                            AbstractBeanFactory.this.beforePrototypeCreation(beanName);

                            Object var1;
                            try {
                                var1 = AbstractBeanFactory.this.createBean(beanName, mbd, args);
                            } finally {
                                AbstractBeanFactory.this.afterPrototypeCreation(beanName);
                            }

                            return var1;
                        }
                    });
                    bean = this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                } catch (IllegalStateException var21) {
                    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", var21);
                }
            }
        } catch (BeansException var23) {
            this.cleanupAfterBeanCreationFailure(beanName);
            throw var23;
        }
    }
    // 9.檢查需要的類型是否符合bean的實際類型
    if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
        try {
            return this.getTypeConverter().convertIfNecessary(bean, requiredType);
        } catch (TypeMismatchException var22) {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", var22);
            }

            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
    } else {
        return bean;
    }
}
  1. 轉換對應beanName
    beanFactory.getBean(String name)傳入的參數,可能是別名,可能是beanName,也可能是FactoryBean,所以需要進行一系列的解析
  2. 嘗試從緩存中加載單例
    單例在Spring的同一個容器內只會被創建一次,後續再獲取bean,就直接從單例緩存中獲取了。如果獲取不成功,則再次嘗試從singletonFactories中加載。因爲在創建bean的時候會存在依賴注入的情況,而在創建依賴的時候爲了避免循環依賴,在Spring中創建bean的原則是不等bean創建完成就會創建bean的ObjectFactory提早曝光加入到緩存中,一旦下一個bean創建時候需要依賴上一個bean則直接使用ObjectFactory
  3. bean的實例化
    如果從緩存中得到了bean的原始狀態,則需要對bean進行實例化。這裏需要說明:緩存中記錄的只是最原始的bean狀態,並不一定是我們最終想要的bean。而getObjectForBeanInstance就是完成這個工作的
  4. 原型模式的依賴檢查
    只有在單例情況下才會嘗試解決循環依賴,如果存在A中有B的屬性,B中有A的屬性,那麼當依賴注入的時候,就會產生A還未創建完的時候因爲對於B的創建再次返回創建A,造成循環依賴,也就是情況isPrototypeCurrentlyInCreation(beanName)判斷true
  5. 檢查parentBeanFactory
    如果緩存沒有數據的話直接轉到父類工程上去加載
  6. 將存儲XML配置文件的GernericBeanDefinition轉換爲RootBeanDefinition
    因爲從XML配置文件中讀取到的Bean信息是存儲在GernericBeanDefinition中的,但是所有的Bean後續處理都是針對於RootBeanDefinition的,所以這裏需要進行一個轉換,轉換的同時如果父類bean不爲空的話,則會一併合併父類的屬性
  7. 尋找依賴
    因爲bean的初始化過程中很可能會用到某些屬性,而某些屬性很可能是動態配置的,並且配置成依賴於其他的bean,那麼這個時候就有必要先加載依賴的bean,所以,在Spring的加載順序中,在初始化某一個bean的時候首先會初始化這個bean所對應的依賴
  8. 針對不同的scope進行bean的創建
    Spring中存在着不同的備scope,其中默認的是singleton,但是還有些其他的配置諸如prototype、request之類的。在這個步驟中,Spring會根據不同的配置進行不同的初始化策略
  9. 類型轉換
    將生產的bean,轉換爲參數requiredType的類型。

FactoryBean

一般情況下,Spring通過反射機制利用bean的class屬性指定實現類來實例化bean。
除此之外,Spring還提供了一個org.springframework.bean.factory.FactoryBean的工廠類接口,用戶可以通過實現該接口定製實例化bean的邏輯。FactoryBean接口對於Spring來說很重要,它隱藏了實例化一些複雜bean的細節。

public interface FactoryBean<T> {
    // 返回由FactoryBean創建的bean實例
    // 如果isSingleton()返回true,則該實例會放到Spring容器中單實例緩存池中
    T getObject() throws Exception;

    // 返回FactoryBean創建的bean類型
    Class<?> getObjectType();

    // 返回由FactoryBean創建的bean實例的作用域是singleton還是prototype
    boolean isSingleton();
}

當配置文件中<bean>的class屬性配置的實現類是FactoryBean時,通過getBean()方法返回的不是FactoryBean本身,而是FactoryBean.getObject()方法所返回的對象,相當於FactoryBean.getObject()代理了getBean()方法

public class Car {
    private int maxSpeed;
    private String brand;
    private double price;
    // get/set
}

如果使用傳統方式配置Car的時候,Car的每個屬性分別對應一個<property>元素標籤
如果用FactoryBean的方式實現就會靈活一些

public class CarFactoryBean implements FactoryBean<Car> {
    private String carInfo;
    public Car getObject() throws Exception {
        Car car = new Car();
        String[] infos = carInfo.split(",");
        car.setBrand(infos[0]);
        car.setMaxSpeed(Integer.valueOf(infos[1]));
        car.setPrice(Double.valueOf(infos[2]));
        return car;
    }
    public Class<Car> getObjectType() {
        return Car.class;
    }
    public boolean isSingleton() {
        return false;
    }
    public String getCarInfo() {
        return this.carInfo;
    }
    public void setCarInfo(String carInfo) {
        this.carInfo = carInfo;
    }
} 

有了這個CarFactoryBean後,就可以如下配置了

<bean id="car" class="com.whyalwaysmea.factorybean.CarFactoryBean"  >
    <property name="carInfo" value="超級跑車,400,20000000" />
</bean>

當調用getBean("car")時,Spring通過反射機制發現CarFactoryBean實現了FactoryBean的接口,這時Spring容器就調用接口方法CarFactoryBean.getObject()方法返回。
如果希望獲取CarFacoryBean的實例,則調用getBean("&car")

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章