Spring 原始碼(一)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();
}
這個構造方法只有三行:
- 註冊內建的BeanPostProcessor的BeanDefinition到容器
- 註冊配置類 BeanDefinition 到容器
- 載入或者重新整理容器中的Bean
容器的初始化過程我認為大致分為:
- 註冊內建的BeanPostProcessor的BeanDefinition到容器
- 註冊配置類 BeanDefinition 到容器
- 解析配置類
- 初始化所有單例Bean,並註冊到容器
AnnotationConfigApplicationContext 總攬
我們來看下AnnotationConfigApplicationContext的類圖:
(進入AnnotationConfigApplicationContext->在Idea類中右鍵 ->檢視類圖)
接下來我們來看具體Spring的相關結構
(類圖使用技巧:右鍵某個介面或者類可對整個類圖的相關類屬性進行檢視,很多時候原始碼沒法看細節性的東西,粗略的看下類結構及方法即可)
AnnotationConfigApplicationContext說明- BeanFactory:它定義了Spring IOC容器最基本的功能規範,主要用來例項化、配置和管理Bean,它是IOC容器容器的心脹。主要包括bean獲取,單例多例判斷,Bean型別及別名獲取
- HierarchicalBeanFactory:繼承BeanFactory介面,新增了
getParentBeanFactory()
- 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延遲例項化