spring架構
Spring是?個分層?常清晰并且依賴關系、職責定位?常明確的輕量級框架,主要包括?個?模塊:數(shù)據處理模塊、Web模塊、AOP(Aspect Oriented Programming)/Aspects模塊、Core Container模塊和 Test 模塊,如下圖所示,Spring依靠這些基本模塊,實現(xiàn)了?個令?愉悅的融合了現(xiàn)有解決?案的零侵?的輕量級框架。

Spring核?容器(Core Container)容器是Spring框架最核?的部分,它管理著Spring應?中bean的創(chuàng)建、配置和管理。在該模塊中,包括了Spring bean??,它為Spring提供了DI的功能?;赽ean??,我們還會發(fā)現(xiàn)有多種Spring應?上下?的實現(xiàn)。所有的Spring模塊都構建于核?容器之上。
?向切?編程(AOP)/Aspects Spring對?向切?編程提供了豐富的?持。這個模塊是Spring應?系統(tǒng)中開發(fā)切?的基礎,與DI?樣,AOP可以幫助應?對象解耦。
數(shù)據訪問與集成(Data Access/Integration)Spring的JDBC和DAO模塊封裝了?量樣板代碼,這樣可以使得數(shù)據庫代碼變得簡潔,也可以更專注于我們的業(yè)務,還可以避免數(shù)據庫資源釋放失敗?引起的問題。 另外,Spring AOP為數(shù)據訪問提供了事務管理服務,同時Spring還對ORM進?了集成,如Hibernate、MyBatis等。該模塊由JDBC、Transactions、ORM、OXM 和 JMS 等模塊組成。
Web 該模塊提供了SpringMVC框架給Web應?,還提供了多種構建和其它應?交互的遠程調??案。 SpringMVC框架在Web層提升了應?的松耦合?平。
Test 為了使得開發(fā)者能夠很?便的進?測試,Spring提供了測試模塊以致?于Spring應?的測試。 通過該模塊,Spring為使?Servlet、JNDI等編寫單元測試提供了?系列的mock對象實現(xiàn)。
IOC
1.什么是IOC
IoC Inversion of Control (控制反轉/反轉控制),注意它是?個技術思想,不是?個技術實現(xiàn)描述的事情:Java開發(fā)領域對象的創(chuàng)建,管理的問題
- 傳統(tǒng)開發(fā)?式:?如類A依賴于類B,往往會在類A中new?個B的對象
- IoC思想下開發(fā)?式:我們不???去new對象了,?是由IoC容器(Spring框架)去幫助我們實例化對象并且管理它,我們需要使?哪個對象,去問IoC容器要即可
我們喪失了?個權利(創(chuàng)建、管理對象的權利),得到了?個福利(不?考慮對象的創(chuàng)建、管理等?系列事情)
為什么叫做控制反轉?
- 控制:指的是對象創(chuàng)建(實例化、管理)的權利
-
反轉:控制權交給外部環(huán)境了(spring框架、IoC容器)
什么是ioc
2.IOC解決了什么問題
IoC解決對象之間的耦合問題

AOP
1.什么是AOP
- AOP: Aspect oriented Programming ?向切?編程/?向??編程
AOP是OOP的延續(xù),從OOP說起 -
OOP三?特征:封裝、繼承和多態(tài)
OOP是?種垂直繼承體系
OOP縱向繼承體系
OOP編程思想可以解決?多數(shù)的代碼重復問題,但是有?些情況是處理不了的,?如下?的在頂級?類
Animal中的多個?法中相同位置出現(xiàn)了重復代碼,OOP就解決不了
重復代碼
2.AOP在解決什么問題,如何解決
- 在不改變原有業(yè)務邏輯情況下,增強橫切邏輯代碼,根本上解耦合,避免橫切邏輯代碼重復
- 「切」:指的是橫切邏輯,原有業(yè)務邏輯代碼我們不能動,只能操作橫切邏輯代碼,所以?向橫切邏輯
「?」:橫切邏輯代碼往往要影響的是很多個?法,每?個?法都如同?個點,多個點構成?,有?個
?的概念在??
1.Spring的生命周期
我們在使用Spring的時候,會創(chuàng)建一個main方法,然后在class上添加@SpringBootApplication注解。在main方法中調用SpringApplication的run方法,之后容器便會啟動。這時我們需要將注意關注到SpringApplication這個類方法上。
SpringApplication
初始化SpringApplication
SpringApplication在初始化時會在構造函數(shù)中調用initialize方法,此方法中主要做了兩件事。
加載設置初始化器對象。
加載設置監(jiān)聽器。
注:初始化器與監(jiān)聽器的加載方式都是采用的Spring SPI擴展,通過讀取META-INF下的spring.factories文件中的值進行初始化。

這里初始化的監(jiān)聽器與初始化器如下:

創(chuàng)建生命周期監(jiān)聽器
SpringApplication初始化完畢后,接下來會調用對應的run方法啟動SpringBoot。首先,我們先看到run方法中的這么一句調用:

此方法中,同樣做了如下兩件事:
初始化SpringApplicationRunListeners,將SpringApplicationRunListener作為參數(shù)初始化
獲取SpringApplicationRunListener同樣采用SPI方式獲取

這里初始化的SpringApplicationRunListener對象如下:

EventPublishingRunListener對象在初始化的時候,會將SpringApplication作為對象傳遞進來。然后創(chuàng)建SimpleApplicationEventMulticaster對象并且將SpringApplication中的監(jiān)聽器傳遞進去。

生命周期Starting
掉用starting后,會遍歷SpringApplicationRunListener中所有的listeners,并調用對應的starting方法。如下所示:

其中根據之前的邏輯,我們可知這個listeners中只有一個EventPublishingRunListener實例對象。EventPublishingRunListener中的starting方法如下所示:

這里我們可以看到首先,封裝了一個ApplicationStartedEvent事件,然后作為參數(shù)執(zhí)行multicastEvent方法。如下所示:


進入到multicastEvent方法后,主要做了如下幾點操作
根據ApplicationEvent獲取對應所有的listener,這里的listener就是之前SpringApplication中在初始化時通過SPI加載的listener。
遍歷執(zhí)行對應listener中的onApplication(Event)方法。
其他生命周期
其他生命周期的調用,與starting一樣,通過構建一個Event事件,然后調用EventPublishingRunListener中的對應方法,在此方法中或找到Application中的listener執(zhí)行對應的邏輯操作。如圖所示:

所以SpringApplicarion的生命周期有如下幾步:

2.BeanFactory
基礎概念
BeanFactory是IOC容器對象的頂級接口,提供了IOC容器最基本的形態(tài),給具體的IOC實現(xiàn)提供了規(guī)范。但是因為BeanFactory這個接口比較原始,無法支持Spring的很多其他插件,所以由這個接口派生出了ApplicationContext接口,通常建議比BeanFactory優(yōu)先。
類圖如下所示

Spring代碼中創(chuàng)建
Spring在SpringApplication.run方法中調用createApplicationContext()獲取ApplicationContext實例對象。默認實例對象為AnnotationConfigEmbeddedWebApplicationContext。如下所示:


在AnnotationConfigEmbeddedWebApplicationContext的父類GenericApplicationContext中,當進行初始化邏輯時,會默認創(chuàng)建一個BeanFactory實例,這個BeanFactory用來初始化IOC容器中的bean對象。

在Spring中ApplicationContext主要子類的裝飾
AnnotationConfigEmbeddedWebApplicationContext
用來讀取注解類,主要是@Configuration、@Component、injext相關注解。允許逐個注冊類(將類名指定為配置位置)以及類路徑掃描(將基本包指定為配置位置)
EmbeddedWebApplicationContext
WebApplicationContext實例,主要用于Servlet相關bean的創(chuàng)建。能夠通過EmbeddedServletContainerFactory工廠類引導創(chuàng)建相關屬性。在這個實例中,會根據EmbeddedServletContainerFactory創(chuàng)建一個EmbeddedServletContainer實例作為容器的上下文,
另外,上下文中定義的任何bean都將自動注冊到嵌入式Servlet容器中。對于單個Servlet bean,將使用“/”映射。如果找到多個Servlet bean,那么小寫的bean名稱將用作映射前綴。任何名為“dispatcherServlet”的Servlet將始終映射到“/”。Filter bean將映射到所有url('/*')。
GenericApplicationContext
包含DefaultListableBeanFactory實例且不采用特定bean定義格式實現(xiàn)的ApplicationContext實例。實現(xiàn)BeanDefinitionRegistry接口,以便允讀取任何的bean定義。
AbstractApplicationContext
實現(xiàn)ApplicationContext的抽象類,主要使用模板模式,提供大量的模板方法供子類實現(xiàn),其中的refresh()方法最為重要,會初始化所有的bean對象也是初始化bean的調用入口,會直接在SpringApplication中調用。
3.BeanDefinition
基礎概念
BeanDefinition接口定義了一套規(guī)范,這套規(guī)范用來描述一個bean的實例,Spring通過掃描@Configuration、@Component等注解生成BeanDefinition實例保存在beanFactory中的beanDefinitionMap中,通過bean name進行索引。
當容器需要初始化某一個bean時,會優(yōu)先通過bean name去beanDefinitionMap中讀取對應的BeanDefinition實例,然后根據屬性信息進行bean的創(chuàng)建。
具體類圖如下所示:

Spring掃描創(chuàng)建BeanDefinition過程
在Spring中,我們可以使用XML、注解、SPI的方式去向容器中注入一個bean實例對象。其中XML與SPI都是采用配置文件的方式直接指定bean的class進行加載,這里我們只說明注解模式下的掃描加載方式。
在上一節(jié)中,我們了解到了BeanFactory的作用是用來創(chuàng)建bean實例的工廠方法,自然BeanDefinition的創(chuàng)建也離不開BeanFactory的影子。首先我們還是先找到創(chuàng)建ApplicationContext的位置(BeanFactory的派生類)。如下圖所示:

我們之前了解到,在①處我們創(chuàng)建了ApplicationContext。但是此時的ApplicationContext中并沒有各個類的BeanDefinition信息,而具體生成是在②處完成。我們進入refreshContext方法后,發(fā)現(xiàn)這個方法執(zhí)行了((AbstractApplicationContext) applicationContext).refresh();進行刷新,而在這個刷新邏輯中會對所有的bean進行IOC注入。如下圖所示:


而SpringBoot對BeanDefinition的掃描在上圖的invokeBeanFactoryPostProcessors方法中執(zhí)行。我們暫時先直接跳到具體的加載邏輯。如下所示:

這里,分三步加載了所有BeanDefinition實例
1.掃描加載所有實現(xiàn)了PriorityOrdered接口的class,目標類為ConfigurationClassPostProcessor其中我們通常使用的@Configuration、@Component等注解都是在此掃描生成BeanDefinition。
2.掃描加載所有實現(xiàn)了Ordered接口的class,主要是三方接入的掃描,比如baidu的disconf
3.掃描加載所有其他的class,如SpringSecuret相關
4.BeanFactoryPostProcessor
基本概念
BeanFactoryPostProcessor為一個接口類,里面僅提供了一個postProcessBeanFactory的方法,入參為BeanFactory的派生類ConfigurableListableBeanFactory。
具體如下所示:

根據里面的入參,我們可知此接口提供了對BeanFactory的自定義操作方式,我們可以通過操作BeanFactory自定義注入相關的BeanDefinition實例,自定義進行bean的注入操作。一般可以作為接入其他組件使用。
SpringBoot調用位置
BeanFactoryPostProcessor在SpringBoot生命周期的refresh中調用如下圖所示:



SpringBoot中大多數(shù)BeanFactoryPostProcessor實例會從BeanFactory中獲取通過getBean方法獲取,所以我們在定義BeanFactoryPostProcessor對象進行注入時,只需要將此class聲明為Bean進行注入即可,SpringBoot會在執(zhí)行Bean初始化前調用BeanFactoryPostProcessor對象。
5.BeanPostProcessor
基本概念
BeanPostProcessor同樣也是一個接口,但是與BeanFactoryPostProcessor不同的是,他們在Bean生命周期中執(zhí)行的位置,接口執(zhí)行的意義都是不一樣的。BeanPostProcessor接口有兩個方法,分別是postProcessBeforeInitialization與postProcessAfterInitialization,入參同樣都是Object bean與String beanName。
具體如下:

此接口為一個鉤子接口,在IOC容器初始化Bean的時候調用,兩個方法分別在Bean初始化時與Bean初始化完成進行調用。用來在Bean的生命周期中進行自定義處理。
有一點需要注意的是BeanPostProcessor是注冊在BeanFactory上的,并不會與某一個class進行綁定,所以在入參中會傳遞進來每一個正在進行初始化或者已經初始化完畢的Bean對象與beanName,我們需要通過此信息與我們想要進行操作的Bean進行匹配,然后執(zhí)行。
SpringBoot調用位置
同樣BeanPostProcessor任然是在refresh方法中進行調用,具體調用路徑如下:



與BeanFactoryPostProcessor不同的是,在refresh中只對BeanPostProcessor進行了注冊,并沒有調用調用邏輯,而且這里同樣也是通過BeanFactory的getBean方法獲取具體的實例,所以我們同樣在實現(xiàn)此實例時只用將其聲明為Bean即可。
具體的執(zhí)行位置如下:









