Spring思維導圖,讓Spring不再難懂
java垃圾回收機制幫助我們實現了這個過程;
而ioc則是讓我們無需考慮物件的建立過程,由ioc容器幫我們實現物件的建立、注入等過程。

【說明】:
Context
對於IoC和DI的理解
BeanFactory
ApplicationContext
Bean
SpEL(#)
引入外部的屬性檔案($)
基於XML的Bean配置
配置Bean
通過全類名
通過工廠方法
通過 FactoryBean
裝配Bean的屬性
通過屬性
通過構造器
基於註解的Bean配置
裝配Bean的屬性
Autowired等註解
配置Bean
Context:componentScan節點
一、控制反轉(Spring IoC)
圖片描述
【說明】:
IoC 概念
應用控制反轉,物件在建立的時候,由一個調控系統內所有物件的外界實體,將其所依賴的物件的引用,傳遞給它。也可以說,依賴注入到物件中。所以,控制反轉是,關於一個物件如何獲取他所依賴的物件的引用,這個責任的反轉。
控制反轉(Inversion of Controll)是一個重要的面向物件程式設計的法則,來削弱計算機程式的耦合問題,也是輕量級 Spring 框架的核心。
控制反轉一般分為兩種型別,依賴注入(Dependency Injection,DI)和依賴查詢(Dependency Lookup),依賴注入應用廣泛。
深入分析
依賴於誰?應用程式依賴於 IoC 容器
為什麼要依賴?應用程式需要 IoC 容器來提供物件需要的外部資源
誰注入誰?IoC容器注入應用程式某個物件,應用程式依賴的物件
注入了社麼?注入某個物件所需要的外部資源(包括物件、資源、常量物件)
與new物件的區別
正轉與反轉,傳統應用程式是由我們將自己在物件中主動控制去直接獲取依賴物件,也就是正轉;而反轉則是由容器來幫助建立及注入依賴物件。
IoC優缺點
優點:實現元件之間的解耦,提供程式的靈活性和可維護性
缺點:物件生成因為是使用反射程式設計,在效率上有損耗
推薦一個交流學習群,614478470 裡面會分享一些資深架構師錄製的視訊錄影:有Spring,MyBatis,Netty原始碼分析,高併發、高效能、分散式、微服務架構的原理,JVM效能優化這些成為架構師必備的知識體系。還能領取免費的學習資源,目前受益良多 點選: ofollow,noindex">加入
二、Spring IoC 容器
【Spring核心元件】 :它們構建起了整個Spring的骨骼架構,沒有它們就不可能有AOP、Web等特性功能。
Core
Context
Bean

Spring解決了一個非常關鍵的問題,它可以讓你對物件之間的關係轉而用配置檔案來管理,或者註解,也就是它的依賴注入機制。而這個注入關係在一個叫Ioc的容器中管理。Ioc容器就是被Bean包裹的物件。Spring正是通過把物件包裝在Bean中從而達到管理這些物件及做一些列額外操作的目的。
1、IoC 容器

概念:
在每個框架中都有一個容器的概念,所謂的容器就是將常用的服務封裝起來,然後,使用者只需要遵循一定的規則,就可以達到統一、靈活、安全、方便、快速的目的
具有依賴注入功能的容器,負責例項化、定位、配置應用程式中的物件及建立這些物件間的依賴
Bean的概念:
由IoC容器管理的那些組成應用程式的物件就叫Bean
Bean就是由Spring容器初始化、裝配及管理的物件,除此之外,Bean就與應用程式中的其他物件沒什麼區別了
元資料 BeanDefinition
確定如何例項化Bean、管理Bean之間的依賴關係及管理Bean,就需要配置元資料,在Spring中由BeanDefintion代表
如何工作(以XML配置方式解釋)
準備配置檔案:配置檔案中宣告 Bean 定義也就是 Bean 配置元資料。
由 IoC 容器進行解析元資料:IoC 容器的 Bean Reader 讀取並解析配置檔案,根據定義生成 BeanDefintion 配置元資料物件,IoC 容器根據 BeanDefintion 進行例項化、配置及組裝 Bean。
例項化 IoC 容器:由客戶端例項化容器,獲取需要的 Bean。
hello world
@Test
public void testHelloWorld() {
// 1、讀取配置檔案例項化一個 IoC 容器
ApplicationContext context = new ClassPathXmlApplicationContext("helloWorld.xml");
// 2、從容器獲取 Bean,主次此處完全“面向介面程式設計”
HelloApi helloApi = context.getBean("hello", HelloApi.class);
// 3、執行業務邏輯
helloApi.sayHello();
}
2、Spring IoC 初始化

3、Spring IoC 容器工作原理

三、核心元件協同工作

Bean : 【演員】Spring 的 bean 例項
Context :【導演】Spring 的上下文
Bean 包裝的是 Object,而 Object 必然有資料,如何給這些資料體提供生存環境就是 Context 要解決的問題,對 Context 來說就是要發現每個 Bean 之間的關係,為它們建立這種關係並維護關係,所以 Context 就是 Bean 關係的集合,這個關係機構叫做 IoC 容器。
Core :【道具】Spring 的核心工具包
建立和維護每個 Bean 之間的關係所需要的一些核心工具包。相當於 Util。
四、BeanFactory 和 ApplicationContext 的區別
IoC 中最核心的介面是 BeanFactory 提供 IoC 的高階服務,而 ApplicationContext 是建立在 BeanFactory 基礎之上提供抽象的面向應用的服務。

BeanFactory
提供了一種先進的配置機制來管理任何種類 Bean 物件,這種配置機制考慮到任何一種可能的儲存方式。
ApplicationContext
建立在 BeanFactory,具有 BeanFactory 的所有功能和行為
MessageSource,提供國際化的訊息服務,擴充套件類 MessageResource 介面
資源訪問,如 URL 和檔案
事件傳播
載入多個(有繼承關係)上下文,使得每一個上下文都專注於一個特定的層次,比如應用的 web 層。
不同點
選用哪個?
BeanFactory:是延遲載入,如果 Bean 的某一個屬性沒有注入,BeanFactory 載入後,直至第一次使用呼叫 getBean 方法才會丟擲異常
ApplicationContext:則在初始化自身時檢驗,這樣有利於檢查所依賴屬性是否注入;所以通常情況下使用 ApplicationContext。
特性表 BeanFatory / ApplicationContext
* Bean 例項化/裝配 YES YES
* 啟動 BeanPostProcessor註冊 NO YES
* 啟動 BeanFactoryPostProcessor註冊 NO YES
* 便捷的 MessageSource反問(i18n) NO YES
* ApplicationEvent 傳送 NO YES
關係
* BeanFactory 提供了配置框架和基本的功能
* ApplicationContext 建立在 BeanFactory 之上,並增加了其他功能
* 一般來說,ApplicationContext 是 BeanFactory 的完全超集,任何 BeanFactory 功能和行為的描述也同樣被認為適用於 ApplicationContext。
五、三種注入方式
在Spring框架中,依賴注入(DI)的設計模式是用來定義物件彼此間的依賴。使用xml配置bean的情況下,它主要有兩種型別:
Setter 方法注入
構造器注入
註解 @autowired
當然,有了註解之後,使用註解的方式更加方便快捷。即自動裝配功能實現屬性自動注入(@autowire)。
六、原理解析
1、Contxt 的初始化過程
當執行 ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
構造方法 ClassPathXmlApplicationContext(String configLocation), 呼叫了 this(new String[] {configLocation}, true, null); 該構造方法具體程式碼:
【ClassPathXmlApplicationContext構造方法】:
/**
* 在 parent 下建立 ClassPathXmlApplicationContext,
* 從 XML 中讀取素有 Bean 定義。
* @param configLocations 配置檔案路徑如 c:simpleContext.xml
* @param refresh 是否需要自動重新整理 context,refrest--> 重新載入
* 載入所有的 bean 定義,建立所有單例。
* refresh 為 true 的時候,根據 context 來手工重新整理
* @param parent the parent context
* @throws BeansException if context creation failed
* @see #refresh()
*/
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException{
// 初始化XmlApplicationContext
super(parent);
// 轉換配置檔案的路徑
setConfigLocations(configLocations);
if(refresh) {
// 重新重新整理所有的 context,這一篇的重點
refresh();
}
}
【refresh方法】:
/**
* 載入或重新整理持久的配置,可能是xml檔案,properties檔案,或者關係型資料庫的概要。
* 作為一啟動方法,如果初始化失敗將會銷燬已經建立好的單例,避免重複載入配置檔案。
* 換句話說,在執行這個方法之後,要不全部載入單例,要不都不載入。
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
// 初始化配置準備重新整理,驗證環境中的一些必選引數
prepareRefresh();
// 告訴繼承銷燬內部的 factory建立新的 factory 例項
// 初始化 Bean 例項
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 初始化 beanFactory 的基本資訊,包括 classLoader、environment、忽略的註解等。
prepareBeanFactory(beanFactory);
try {
// beanFactory 內部的 postProces,可以理解為 context 中的 PostProcess 的補充
beanFactory.postProcessBeanFactory(beanFactory)p;
// 執行 BeanFactoryPostProcessor(在beanFactory)初始化過程中,bean 初始化之前,修改BeanFactory 引數
// BeanDefinitionRegistryPostProcessor 其實也是繼承自 BeanFactoryPostProcessor,
// 多個對 BeanDefinitionRegistry 的支援 invokeBeanFactoryPostProcessors(beanFactory)
// 執行 postProcess,那 BeanPoseProcessor 是什麼呢,是為了在 bean 載入過程中修改 bean 的內容,
// 使用Before、After分別對應初始化前和初始化後
registerBeanPostProcessors(beanFactory);
// 初始化 MessageSource,主要用於 I18N 本地化的內容
initMessageSource();
// 初始化事件廣播 ApplicationEventMulticaster,使用觀察者模式,對註冊的 ApplicationEvent 時間進行捕捉
initApplicationEventMulticaster();
// 初始化特殊的 bean 方法
onRefresh();
// 將所有 ApplicationEventListener 註冊到 ApplicationEventMulticaster 中
registerListeners();
// 初始化所有部位 lazy-init 的bean,singleton 例項
finishBeanFactoryInitialization(beanFactory);
// 初始化 lifeCycle 的bean啟動(例如 quartz 的定時器),如果開啟 JMX 則將 ApplicationContext 註冊到上面
finishRefresh();
}
catch(BeansException ex) {
// 銷燬已經建立單例
resources.destroyBeans();
// 將 context 的狀態轉換為無效,標示初始化失敗
flag.cancelRefresh(ex);
}
}
}
2、從時序圖看上述啟動初始化
【容器初始化時序圖】 :

推薦一個交流學習群,614478470 裡面會分享一些資深架構師錄製的視訊錄影:有Spring,MyBatis,Netty原始碼分析,高併發、高效能、分散式、微服務架構的原理,JVM效能優化這些成為架構師必備的知識體系。還能領取免費的學習資源,目前受益良多 點選: 加入