1. 程式人生 > >spring原始碼學習之路---IOC初探(一)

spring原始碼學習之路---IOC初探(一)

首先把spring原始碼匯入,怎麼匯入百度下。
首先我們來說一下IOC,IOC是spring最核心的理念,包括AOP也要屈居第二,那麼IOC到底是什麼呢,四個字,控制反轉。

網上有不少是這麼解釋IOC的,說IOC是將物件的建立和依賴關係交給容器,這句話我相信不少人都知道,在我個人的理解,IOC就是讓我們的開發變的更簡單了。

為什麼這麼說呢,光說沒意思,直接上程式碼。

public class Person {

    public void work(){
        System.out.println("I am working");
    }
}

上面這個是Person類,如果我們還有一個Company公司類,公司要開張需要人來工作,所以我們可能需要這樣。

public class Company {

    @Autowired
    public Person person;

    public void open(){
        person.work();
        System.out.println("I am opening");
    }
}

好了,這樣可以了,雖說和現實有些區別,畢竟沒有一個人的公司,但是就是這麼個意思。必須要有人在公司裡,公司才能開張。

有了spring上述情況我們是怎麼寫的呢?Person類不變,Company就可以簡單些了。

public class Company {
@Autowired public Person person; public void open(){ person.work(); System.out.println("I am opening"); } }

OK了,使用註解後,spring裡的寫法是這樣的,是不是簡單很多?或許你可能會說,這才減少了多少程式碼,但是事實上是,真正的專案中,不可能有這麼簡單的依賴關係,或許是2層,3層甚至N層。

當然,可能我們有時候用的XML,XML和註解的區別就在於這裡,註解可以快速的完成依賴的注入,但是缺點也很明顯,那就是比如我公司裡不需要人了,我需要的是機器,那麼我還要手動改程式碼,將Person換成機器(這裡應該是英文,英語不好,懶得查了,只記得念“磨洗”),而如果是XML配置,那麼我們只需要改下配置檔案就可以。維護起來會方便很多,當然XML的缺點也很明顯,那就是依賴關係複雜的時候,XML檔案會比較臃腫,所以我們一般的做法是將XML分離開來。

說到這裡,有些扯遠了,但是我覺得以上可以足夠說明IOC的好處,知道了IOC的好處,我們自然就要知道怎麼來實現IOC了。

或許看了spring的原始碼,第一感覺是很蒙,包太多,我也很蒙,但是研究東西就是得沉下心來,先來關注一下這個介面,BeanFactory,附上程式碼。

package org.springframework.beans.factory;

import org.springframework.beans.BeansException;

/*
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @since 13 April 2001
 */
public interface BeanFactory {

    String FACTORY_BEAN_PREFIX = "&";


    Object getBean(String name) throws BeansException;


    <T> T getBean(String name, Class<T> requiredType) throws BeansException;


    <T> T getBean(Class<T> requiredType) throws BeansException;


    Object getBean(String name, Object... args) throws BeansException;


    boolean containsBean(String name);


    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;


    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;


    boolean isTypeMatch(String name, Class targetType) throws NoSuchBeanDefinitionException;


    Class<?> getType(String name) throws NoSuchBeanDefinitionException;


    String[] getAliases(String name);

}

這個便是spring核心的Bean工廠定義,上面的author說是2001年寫的,已經歷史久遠了,這個類是spring中所有bean工廠,也就是俗稱的IOC容器的祖宗,各種IOC容器都只是它的實現或者為了滿足特別需求的擴充套件實現,包括我們平時用的最多的ApplicationContext。從上面的方法就可以看出,這些工廠的實現最大的作用就是根據bean的名稱亦或型別等等,來返回一個bean的例項。

一個工廠如果想擁有這樣的功能,那麼它一定需要以下幾個因素:

1.需要持有各種bean的定義,否則無法正確的完成bean的例項化。

2.需要持有bean之間的依賴關係,否則在bean例項化的過程中也會出現問題。例如上例,如果我們只是各自持有Person和Company,卻不知道他們的依賴關係,那麼在Company初始化以後,呼叫open方法時,就會報空指標。這是因為Company其實並沒有真正的被正確初始化。

3.以上兩種都要依賴於我們所寫的依賴關係的定義,暫且認為是XML檔案(其實可以是各種各樣的),那麼我們需要一個工具來完成XML檔案的讀取。

我目前想到的,只需要滿足以上三種條件,便可以建立一個bean工廠,來生產各種bean。當然,spring有更高階的做法,以上只是我們直觀的去想如何實現IOC。

其實在上述過程中仍舊有一些問題,比如第一步,我們需要持有bean的定義,如何持有?這是一個問題。我們知道spring的XML配置檔案中,有一個屬性是lazy-init,這就說明,bean在何時例項化我們是可以控制的。這個屬性預設是false,但是我們可以將這個屬性設定為true,也就是說spring容器初始化以後,配置了延遲載入的各種bean都還未產生,它們只在需要的時候出現。

所以我們無法直接的建立一個Map

package org.springframework.beans.factory.config;

import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.core.AttributeAccessor;


public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {


    String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;


    String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;


    int ROLE_APPLICATION = 0;


    int ROLE_SUPPORT = 1;


    int ROLE_INFRASTRUCTURE = 2;


    String getParentName();


    void setParentName(String parentName);


    String getBeanClassName();


    void setBeanClassName(String beanClassName);


    String getFactoryBeanName();


    void setFactoryBeanName(String factoryBeanName);


    String getFactoryMethodName();


    void setFactoryMethodName(String factoryMethodName);


    String getScope();


    void setScope(String scope);


    boolean isLazyInit();


    void setLazyInit(boolean lazyInit);


    String[] getDependsOn();


    void setDependsOn(String[] dependsOn);


    boolean isAutowireCandidate();


    void setAutowireCandidate(boolean autowireCandidate);


    boolean isPrimary();


    void setPrimary(boolean primary);


    ConstructorArgumentValues getConstructorArgumentValues();


    MutablePropertyValues getPropertyValues();


    boolean isSingleton();


    boolean isPrototype();


    boolean isAbstract();


    int getRole();


    String getDescription();


    String getResourceDescription();


    BeanDefinition getOriginatingBeanDefinition();

}

顧名思義,這個便是spring中的bean定義介面,所以其實我們工廠裡持有的bean定義,就是一堆這個玩意,或者是他的實現類和子介面。這個介面並非直接的祖宗介面,他所繼承的兩個介面一個是core下面的AttributeAccessor,繼承這個介面就以為這我們的bean定義介面同樣具有處理屬性的能力,而另外一個是beans下面的BeanMetadataElement,字面翻譯這個介面就是bean的元資料元素,它可以獲得bean的配置定義的一個元素。在XML檔案中來說,就是會持有一個bean標籤。

仔細觀看,能發現beanDefinition中有兩個方法分別是String[] getDependsOn()和void setDependsOn(String[] dependsOn),這兩個方法就是獲取依賴的beanName和設定依賴的beanName,這樣就好辦了,只要我們有一個BeanDefinition,就可以完全的產生一個完整的bean例項。

轉載自http://www.cnblogs.com/zuoxiaolong