1. 程式人生 > 實用技巧 >Spring 原始碼(一)Spring 容器的入口及簡單介紹

Spring 原始碼(一)Spring 容器的入口及簡單介紹

說明: 1.本篇不講述具體的Spring相關功能原始碼分析,僅對原始碼導讀的一些前提做一些準備和記錄

Spring 容器的初始化

ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);

當我們完成一個ApplicationContext的例項化時就完成了Spring容器的初始化,而AnnotationConfigApplicationContext的構造方法也就是Spring容器的入口。

(IDEA當中可通過crtl+滑鼠左鍵進入原始碼檢視 ,此處我已簡單的方式進行)

// 初始化容器
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
    // 註冊 Spring 內建後置處理器的 BeanDefinition 到容器
    this();
    // 註冊配置類 BeanDefinition 到容器
    register(annotatedClasses);
    // 載入或者重新整理容器中的Bean
    refresh();
}

這個構造方法只有三行:

  1. 註冊內建的BeanPostProcessor的BeanDefinition到容器
  2. 註冊配置類 BeanDefinition 到容器
  3. 載入或者重新整理容器中的Bean

容器的初始化過程我認為大致分為:

  1. 註冊內建的BeanPostProcessor的BeanDefinition到容器
  2. 註冊配置類 BeanDefinition 到容器
  3. 解析配置類
  4. 初始化所有單例Bean,並註冊到容器

AnnotationConfigApplicationContext 總攬

我們來看下AnnotationConfigApplicationContext的類圖:

(進入AnnotationConfigApplicationContext->在Idea類中右鍵 ->檢視類圖)

接下來我們來看具體Spring的相關結構

(類圖使用技巧:右鍵某個介面或者類可對整個類圖的相關類屬性進行檢視,很多時候原始碼沒法看細節性的東西,粗略的看下類結構及方法即可)

AnnotationConfigApplicationContext說明
  • BeanFactory:它定義了Spring IOC容器最基本的功能規範,主要用來例項化、配置和管理Bean,它是IOC容器容器的心脹。主要包括bean獲取,單例多例判斷,Bean型別及別名獲取

  • HierarchicalBeanFactory:繼承BeanFactory介面,新增了getParentBeanFactory()
    方法,使BeanFactory具備了雙親IOC容器的管理功能。

  • ListableBeanFactory:細化了許多BeanFactory介面的功能,比如getBeanDefinitionNames()方法(獲取容器中所有Bean定義的名稱)。

  • ResourceLoader:資源載入器。

  • MessageSource:支援不同的資訊源,從而實現國際化。

  • ApplicationEventPublisher:支援應用事件,提供事件機制的定義。

  • EnvironmentCapable:提供了對環境變數的支援。

  • ApplicationContext:它繼承了上述所有介面,是IOC容器的高階形態,它定了一個完成容器的雛形。(重點的類需要稍微記一下 方便後續進行回顧學習)

  • AbstractApplicationContext:一個容器的抽象實現

使用者使用容器時,可以使用轉義符"&"來得到FactoryBean本身,如果不加則是獲取FactoryBean產生的物件。

BeanFactory和FactoryBean的區別

  • BeanFactory:它是對IOC容器所有Bean進行管理,如例項化,配置和獲取容器中的Bean。
  • FactoryBean:它是一個能夠生產或者修飾物件生成的工廠Bean。

BeanFactory :(通用bean處理)

  BeanFactory 是基礎型別的 IoC 容器,它由 org.springframework.beans.facytory.BeanFactory 介面定義,並提供了完整的 IoC 服務支援。簡單來說,BeanFactory 就是一個管理 Bean 的工廠,它主要負責初始化各種 Bean,並呼叫它們的生命週期方法。
BeanFactory 介面有多個實現類,最常見的是 org.springframework.beans.factory.xml.XmlBeanFactory,它是根據 XML 配置檔案中的定義裝配 Bean 的。
建立 BeanFactory 例項時,需要提供 Spring 所管理容器的詳細配置資訊,這些資訊通常採用 XML 檔案形式管理。其載入配置資訊的程式碼具體如下所示:

BeanFactory beanFactory = new XmlBeanFactory(new FileSystemResource("D://applicationContext.xml"));

FactoryBean:(複雜自定義bean處理)

  一般情況下,Spring通過反射機制利用<bean>的class屬性指定實現類例項化Bean,在某些情況下,例項化Bean過程比較複雜,如果按照傳統的方式,則需要在<bean>中提供大量的配置資訊。配置方式的靈活性是受限的,這時採用編碼的方式可能會得到一個簡單的方案。Spring為此提供了一個org.springframework.bean.factory.FactoryBean的工廠類介面,使用者可以通過實現該介面定製例項化Bean的邏輯。FactoryBean介面對於Spring框架來說佔用重要的地位,Spring自身就提供了70多個FactoryBean的實現。它們隱藏了例項化一些複雜Bean的細節,給上層應用帶來了便利。從Spring3.0開始,FactoryBean開始支援泛型,即介面宣告改為FactoryBean<T>的形式 下面簡單給一個FactoryBean的例子 1.Bean的Resourse配置
<beans xmlns="http://www.springframework.org/schema/beans"  
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
             xmlns:context="http://www.springframework.org/schema/context"  
             xmlns:aop="http://www.springframework.org/schema/aop"  
             xmlns:tx="http://www.springframework.org/schema/tx"  
             xsi:schemaLocation="http://www.springframework.org/schema/beans  
                     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
                     http://www.springframework.org/schema/context  
                     http://www.springframework.org/schema/context/spring-context-3.0.xsd  
                     http://www.springframework.org/schema/aop  
                     http://www.springframework.org/schema/aop/spring-aop-3.0.xsd  
                     http://www.springframework.org/schema/tx  
                     http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">  
      
 <bean id="student" class="com.spring.bean.Student">    
  <property name="name" value="zhangsan" />    
 </bean>    
   
 <bean id="school" class="com.spring.bean.School">    
 </bean>   
   
 <bean id="factoryBeanPojo" class="com.spring.bean.FactoryBeanPojo">    
    <property name="type" value="student" />  
 </bean>   
</beans>

2.FactoryBean的實現類 實現FactoryBean 實現其介面方法 重寫getObject等其他bean方法

import org.springframework.beans.factory.FactoryBean;  
  
public class FactoryBeanPojo implements FactoryBean{  
    private String type;  
  
    @Override  
    public Object getObject() throws Exception {  
        if("student".equals(type)){  
            return new Student();             
        }else{  
            return new School();  
        }  
          
    }  
  
    @Override  
    public Class getObjectType() {  
        return School.class;  
    }  
  
    @Override  
    public boolean isSingleton() {  
        return true;  
    }  
  
    public String getType() {  
        return type;  
    }  
  
    public void setType(String type) {  
        this.type = type;  
    }  
      
}

3.普通bean註冊

public class School {  
    private String schoolName;  
    private String address;  
    private int studentNumber;  
    public String getSchoolName() {  
        return schoolName;  
    }  
    public void setSchoolName(String schoolName) {  
        this.schoolName = schoolName;  
    }  
    public String getAddress() {  
        return address;  
    }  
    public void setAddress(String address) {  
        this.address = address;  
    }  
    public int getStudentNumber() {  
        return studentNumber;  
    }  
    public void setStudentNumber(int studentNumber) {  
        this.studentNumber = studentNumber;  
    }  
    @Override  
    public String toString() {  
        return "School [schoolName=" + schoolName + ", address=" + address  
                + ", studentNumber=" + studentNumber + "]";  
    }  
}

public class Student {  
    private String name;    
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
}


 4.測試

import org.springframework.context.support.ClassPathXmlApplicationContext;  
  
import com.spring.bean.FactoryBeanPojo;  

public class FactoryBeanTest {  
    public static void main(String[] args){  
        String url = "com/spring/config/BeanConfig.xml";  
        ClassPathXmlApplicationContext cpxa = new ClassPathXmlApplicationContext(url);  
     //Bean工廠獲取FactoryBean來獲取bean
        Object school=  cpxa.getBean("factoryBeanPojo");  
     //獲取自定義BeanFactory工廠   需要加&符號來標識
        FactoryBeanPojo factoryBeanPojo= (FactoryBeanPojo) cpxa.getBean("&factoryBeanPojo");  

        System.out.println(school.getClass().getName());  
        System.out.println(factoryBeanPojo.getClass().getName());  
    }  
}

  結果:

com.spring.bean.Student 
com.spring.bean.FactoryBeanPojo

  總結:BeanFacoty是SpringIOC容器的預設Bean管理,通過Factotybean可以自定義一些複雜的Bean

BeanFactory和ApplicationContext的區別

通過繼承圖我們可以發現

  • BeanFactory是容器的基本定義。
  • ApplicationContext繼承自BeanFactory,是容器的高階形態,在BeanFactory的基礎上添加了許多對高階容器特性的支援。

其次:

BeanFactory:

BeanFactory在啟動的時候不會去例項化Bean,有從容器中拿Bean的時候才會去例項化;

ApplicationContext:

ApplicationContext在啟動的時候就把所有的Bean全部例項化了。它還可以為Bean配置lazy-init=true來讓Bean延遲例項化