在以前的5個文章中咱們已經對 IOC, DI, AOP 和配置相關進行了一些瞭解,相信在此基礎上能夠幫助你們更好地去閱讀 Spring 的源碼git
1.這裏的源碼版本號爲 version 5.1.3.RELEASEgithub
2.源碼獲取地址 github.com/spring-proj…spring
3.jdk要在1.8以上,spring5中大量使用了lambda表達式,而lambda表達式在1.8後開始支持編程
4.使用指南:spring.io/guides數據結構
5.各個版本的介紹:github.com/spring-proj…maven
6.Spring5.x的版本新特性:github.com/spring-proj…ide
1.用戶配置bean定義 ---> 2.IOC容器加載bean定義
---> 3.IOC容器建立bean實例 ---> 4.使用IOC容器
複製代碼
使用Spring的入口爲:ApplicationContext
ApplicationContext context = new ClassPathXmlApplicationContext(...Service.xml);
前期準備:
建立一個maven工程,僅引入Spring-Context包(注意版本號)便可
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>
複製代碼
內部隱藏的BeanFactory是不多被關注的,提供給用戶直觀看到的就是ApplicationContext,我使用的是IDEA,能夠點擊類後打開navigate選項---Type Hierarchy---選擇SuperTypes Hierarchy,觀看它的繼承體系,如下是它做爲一個接口,又繼承了什麼接口post
既然它繼承了上面6個接口,那它一定會有這6個接口相關的行爲學習
EnvironmentCapable:取環境相關的參數,.properties文件
ListableBeanFactory:提供BeanFactorys行爲
HierarchicalBeanFactory:父子容器
---提供bean分層管理的方式
且父容器沒法訪問子容器,子容器能夠訪問父容器,就好比只有兒子問老爸拿錢,沒有父親問兒子要錢的
MethodSource:國際化
ApplicationEventPublisher:應用的事件發佈,好比應用的開啓,結束,銷燬等等
ResourcePatternResolver:加載Resource
複製代碼
這些在後面咱們再展開來說···ui
那如何先大體地查看這幅圖
先看 ConfigurableApplicationContext 這一大塊,
ConfigurableApplicationContext 如下全是抽象的,一直到 FileSystemXmlApplicationContext
和 ClassPathXmlApplicationContext 兩個xml配置方式的具體實現,
而下面的 GenericApplicationContext 則是通用實現,其中包括了通用xml,靜態,動態語言Groovy和註解,
通用xml實現 GenericXmlApplicationContext 支持 FileSystemXmlApplicationContext 和 ClassPathXmlApplicationContext,
則不管放到文件系統或者classpath均可以
兩大塊 AbstractRefreshableApplicationContext 和 GenericApplicationContext
都繼承了 AbstractApplicationContext
複製代碼
做爲一個接口確定加入了某些行爲,咱們參考圖左 structure 處,而後比照源碼片斷
此處加入了應用監聽器,確定是使用了觀察者模式,裏面發生的事件均可以往外提供發佈
經過這個 listener 就能夠獲取到
複製代碼
此處看名字是否會有熟悉的感受,若是沒有,能夠回顧下 手寫Spring---AOP面向切面編程(4)
在手寫AOP的時候,postProcessor已經被說起,講到了beanFactory如何可以靈活擴展,
可是咱們當時講的是BeanPostProcessor,是對bean的建立過程實現階段動態加強
那爲何如今這個是 BeanFactoryPostProcessor 呢,那就是它把工廠的建立過程也引入了各個階段
並且提供了各個階段支持動態加強的功能
ApplicationContext會幫咱們完成bean定義的加載,解析等一系列過程,在此過程當中咱們可能須要靈活加入一些處理
複製代碼
這裏的refresh方法是刷新,刷新bean定義,IOC容器裏面的bean實例
複製代碼
此類中已經提供了不少的接口方法的實現,並且裏面的定義都廣泛具備了數據結構的支持
須要注意的是 registerBeanPostProcessors() 方法是保護類型的,只能供子類調用
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
複製代碼
以前說起到的 HierarchicalBeanFactory --- 父子容器在這裏也有體現
好比它的一個構造器,此時這裏父容器就已經給進來了
@Nullable
private ApplicationContext parent;
public AbstractApplicationContext(@Nullable ApplicationContext parent) {
this();
setParent(parent);
}
複製代碼
此時再看看在setParent()方法中,大體就是取得父容器的環境參數,而後進行一個比較 instanceof 與合併 merge 的事情
@Override
public void setParent(@Nullable ApplicationContext parent) {
this.parent = parent;
if (parent != null) {
Environment parentEnvironment = parent.getEnvironment();
if (parentEnvironment instanceof ConfigurableEnvironment) {
getEnvironment().merge((ConfigurableEnvironment) parentEnvironment);
}
}
}
複製代碼
而在此實現後的繼續深刻擴展就是 AbstractRefreshableApplicationContext 和 AbstractRefreshableConfigApplicationContext , 剛剛在 ConfigurableApplicationContext 的第 ③ 點不是說起了一個 refresh() 方法嗎,第一個就是可支持刷新的,第二個就是可支持刷新且又被配置的,再以後就是 xml 的了,咱們如今先不細說
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry
複製代碼
此時往下看
不難發現構造方法中,只有默認的 beanFactory 和父容器 parent 等做爲參數,並無說起咱們能夠給入 beanDefinition 的來源,好比 xml文件等等
private final DefaultListableBeanFactory beanFactory;
// 構造方法:
// 若是你沒有傳入beanFactory,那就是默認的
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
// 也能夠本身提供
public GenericApplicationContext(DefaultListableBeanFactory beanFactory) {
Assert.notNull(beanFactory, "BeanFactory must not be null");
this.beanFactory = beanFactory;
}
複製代碼
和上面同樣的套路,提供了setParent()方法
@Override
public void setParent(@Nullable ApplicationContext parent) {
super.setParent(parent);
this.beanFactory.setParentBeanFactory(getInternalParentBeanFactory());
}
複製代碼
//---------------------------------------------------------------------
// Implementations of AbstractApplicationContext's template methods
//---------------------------------------------------------------------
/**
* Do nothing: We hold a single internal BeanFactory and rely on callers
* to register beans through our public methods (or the BeanFactory's).
* @see #registerBeanDefinition
*/
@Override
protected final void refreshBeanFactory() throws IllegalStateException {
if (!this.refreshed.compareAndSet(false, true)) {
throw new IllegalStateException(
"GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
}
this.beanFactory.setSerializationId(getId());
}
@Override
protected void cancelRefresh(BeansException ex) {
this.beanFactory.setSerializationId(null);
super.cancelRefresh(ex);
}
複製代碼
這樣下來,咱們能大體瞭解最外層的 ApplciationContext 是如何一步步加入哪些參數的
此篇只是大體地看了一下 ApplicationContext 的子類所擁有的一些東西,可能你們看起來會以爲一頭霧水,下一篇會結合實例去進行使用而後一步步進行分析,可能篇幅就會增長。
有人反映了篇幅過長的問題,因此如今秉承少吃多餐的原則去慢更,望多多總結,互相進步··