常用架構彙總
先來看常用架構的知識點彙總,如下圖所示。

如上圖所示,左上方是 Spring 系列。很多研發人員把 Spring 看作心目中最好的 Java 項目,沒有之一。Spring 系列包含非常多的項目,可以滿足 Java 開發中的方方面面。那麼來看幾個常用的 Spring 架構。
Spring
Spring Framework,也就是我們常說的 Spring 架構,包括了 IoC 依賴注入,Context 上下文、 Bean 管理、SpringMVC 等衆多功能子產品,其他 Spring 項目比如 Spring Boot 也會依賴 Spring 架構。
Spring Boot 的目标是簡化 Spring 應用和服務的建立、開發與部署,簡化了配置檔案,使用嵌入式 Web 伺服器,含有諸多開箱即用的微服務功能,可以和 Spring Cloud 聯合部署。Spring Boot 的核心思想是約定大于配置,應用隻需要很少的配置即可,簡化了應用開發模式。
Spring Data 是一個資料通路及操作的工具集,封裝了多種資料源的操作能力,包括:JDBC、Redis、MongoDB 等。
Spring Cloud 是一套完整的微服務解決方案,是一系列不同功能的微服務架構的集合。Spring Cloud 基于 Spring Boot,簡化了分布式系統的開發,內建了服務發現、配置管理、消息總線、負載均衡、斷路器、資料監控等各種服務治理能力。比如sleuth提供了全鍊路追蹤能力,Netflix套件提供了hystrix熔斷器、zuul網關等衆多的治理元件。config 元件提供了動态配置能力,bus元件支援使用 RabbitMQ、Kafka、ActiveMQ 等消息隊列,實作分布式服務之間的事件通信。
Spring Security 用于快速建構安全的應用程式和服務,在 Spring Boot 和 Spring Security OAuth2 的基礎上,可以快速實作常見安全模型,如單點登入,令牌中繼和令牌交換。這裡可以了解一下 OAuth2 授權機制和 JWT 認證方式。OAuth2 是一種授權機制,規定了完備的授權、認證流程。JWT 全稱是 JSON Web Token,是一種把認證資訊包含在 token 中的認證實作,OAuth2 授權機制中就可以應用 JWT 來作為認證的具體實作方法。
Struts
Struts 是曾經非常火爆的 Web 組合 SSH 中的控制層。我們知道 Web 服務一般都采用 MVC 分層模型建構,就是 Model 層負責内部資料模型,Controller 負責請求的分發控制,View 層負責傳回給使用者展示的視圖。Struts 實作的就是其中控制層的角色。
Struts 采用 Filter 實作,針對類進行攔截,每次請求就會建立一個 Action。不過使用 Struts 的 SSH 組合已經逐漸被使用 SpringMVC 的 SSM 組合代替,也就是 SpringMVC+Spring+MyBatis的組合,一方面原因是由于 Struts 對幾次安全漏洞的處理,讓大家對 Struts 的信心受到影響;另一方面,SpringMVC 更加靈活,不需要額外配置,不存在和 Spring 整合等問題,使用更加友善。是以建議以 SSM 架構的學習為主。
ORM
ORM 就是對象關系比對,解決面向對象與關系資料庫存在的互不比對的問題。簡單來說,就是把關系資料庫中的資料轉換成面向對象程式中的對象。常用的 ORM 架構有 Hibernate 和 MyBatis,也就是 SSH 組合和 SSM 組合中的 H 與 M。
來看一下 Hibernate 和 MyBatis 的特點和差別。
●Hibernate 對資料庫結構提供了完整的封裝,實作了 POJO 對象與資料庫表之間的映射,能夠自動生成并執行 SQL 語句。隻要定義了 POJO 到資料庫表的映射關系,就可以通過 Hibernate 提供的方法完成資料庫操作。Hibernate 符合 JPA 規範,就是 Java 持久層 API。
●MyBatis 通過映射配置檔案,将 SQL 所需的參數和傳回的結果字段映射到指定對象,MyBatis 不會自動生成 SQL,需要自己定義 SQL 語句,不過更友善對 SQL 語句進行優化。
總結起來,Hibernate 配置要比 MyBatis 複雜的多,學習成本也比 MyBatis 高。MyBatis,簡單、高效、靈活,但是需要自己維護 SQL;Hibernate 功能強大、全自動、适配不同資料庫,但是非常複雜,靈活性稍差。
Netty 是一個高性能的異步事件驅動的網絡通信架構,Netty 對 JDK 原生 NIO 進行封裝,簡化了網絡服務的開發。
另外,同類型的架構還有 MINA、Grizzly,不過目前使用得相對較少,一般不會在面試題目中出現,可以作為興趣簡單了解。
RPC
RPC 服務,Motan、Dubbo、gRPC 都是比較常用的高性能 RPC 架構,可以提供完善的服務治理能力,Java 版本的通信層都是基于前面提到的 Netty 實作。
其他
此外,Jersy 和 RESTEasy 都是可以快速開發 RESTful 服務的架構。與 SpringMVC 相比,這兩個架構都是基于 JAX-RS 标準,而 SpringMVC 基于 Servlet,使用自己建構的 API,是兩個不同的标準。
Shiro 架構是一個與 Spring Security 類似的開源的權限管理架構,用于通路授權、認證、加密及會話管理。能夠支援單機與分布式 session 管理。相比 Security,Shiro更加簡單易用。
詳解 Spring 架構
對于 Spring 架構,講解中涉及的流程與實作預設都是基于最新的 5.x 版本。先來看 Spring 中的幾個重要概念。
IoC
IoC,也就是控制反轉,如下圖,拿公司招聘崗位來舉例。假設一個公司有産品、研發、測試等崗位。如果是公司根據崗位要求,逐個安排人選,如圖中向下的箭頭,這是正向流程。如果反過來,不用公司來安排候選人,而是由第三方獵頭來比對崗位和候選人,然後進行推薦,如圖中向上的箭頭,這就是控制反轉。
在 Spring 中,對象的屬性是由對象自己建立的,就是正向流程;如果屬性不是對象建立,而是由 Spring 來自動進行裝配,就是控制反轉。這裡的 DI 也就是依賴注入,就是實作控制反轉的方式。正向流程導緻了對象于對象之間的高耦合,IoC 可以解決對象耦合的問題,有利于功能的複用,能夠使程式的結構變得非常靈活。
Context 和 Bean
Spring 進行 IoC 實作時使用的兩個概念:Context 上下文和 Bean。如下圖所示,所有被 Spring 管理的、由 Spring 建立的、用于依賴注入的對象,就叫作一個 Bean。Spring 建立并完成依賴注入後,所有 Bean 統一放在一個叫作 Context 的上下文中進行管理。
AOP
AOP,就是面向切面程式設計。如下圖所示,一般我們的程式執行流程是從 Controller 層調用 Service 層、然後 Service 層調用 DAO 層通路資料,最後在逐層傳回結果。這個是圖中向下箭頭所示的按程式執行順序的縱向處理。
但是,我們思考這樣一個問題,一個系統中會有多個不同的服務,例如使用者服務、商品資訊服務等等,每個服務的Controller層都需要驗證參數,都需要處理異常,如果按照圖中紅色的部分,對不同服務的縱向處理流程進行橫切,在每個切面上完成通用的功能,例如身份認證、驗證參數、處理異常等等、這樣就不用在每個服務中都寫相同的邏輯了,這就是 AOP 思想解決的問題。AOP 以功能進行劃分,對服務順序執行流程中的不同位置進行橫切,完成各服務共同需要實作的功能。
元件
再來看到 Spring 架構,下圖中列出了 Spring 架構主要包含的元件。這張圖來自 Spring4.x 的文檔。目前最新的 5.x 版本中右面的 Portlet 元件已經被廢棄掉,同時增加了用于異步響應式處理的 WebFlux 元件。這裡不需要對所有的元件都詳細了解,隻需要重點了解最常用的幾個元件實作,以及知道每個元件用來實作哪一類功能就可以了。
圖中紅框框住的是比較重要的元件,Core 元件是 Spring 所有元件的核心;Bean 元件和 Context 元件我剛才提到了,是實作 IoC 和依賴注入的基礎;AOP 元件用來實作面向切面程式設計;Web 元件包括 SpringMVC,是 Web 服務的控制層實作。
動态代理和靜态代理
接下來是 Spring 中機制和概念相關的知識點,如下圖所示。
AOP 的實作是通過代理模式,在調用對象的某個方法時,執行插入的切面邏輯。實作的方式有動态代理,也叫運作時增強,比如 JDK 代理、CGLIB;靜态代理是在編譯時進行織入或類加載時進行織入,比如 AspectJ。關于 AOP 還需要了解一下對應的 Aspect、pointcut、advice 等注解和具體使用方式。
PlaceHolder 動态替換
PlaceHolder 動态替換主要需要了解替換發生的時間,是在 Bean Definition 建立完成後,Bean 初始化之前,是通過 BeanFactoryPostProcessor 接口實作的。主要實作方式有 PropertyPlaceholderConfigurer 和 PropertySourcesPlaceholderConfigurer。這兩個類實作邏輯不一樣,Spring Boot 使用 PropertySourcesPlaceholderConfigurer 實作。
事務
事務,需要了解 Spring 中對事務規定的隔離類型和事務傳播類型。這裡要知道事務的隔離級别是由具體的資料庫來實作的,在資料庫部分會作詳細介紹。事務的傳播類型,可以重點了解最常用的 REQUIRED 和 SUPPORTS類型。
核心接口/類
再來看圖右上方需要重點掌握的核心類。
●ApplicationContext 儲存了 IoC 的整個應用上下文,可以通過其中的 BeanFactory 擷取到任意到 Bean;
●BeanFactory 主要的作用是根據 Bean Definition 來建立具體的 Bean;
●BeanWrapper 是對 Bean 的包裝,一般情況下是在 Spring IoC 内部使用,提供了通路 Bean 的屬性值、屬性編輯器注冊、類型轉換等功能,友善 IoC 容器用統一的方式來通路 Bean 的屬性;
●FactoryBean 通過 getObject 方法傳回實際的 Bean 對象,例如 Motan 架構中 referer 對 service 的動态代理就是通過 FactoryBean 來實作的。
Scope
Bean 的 Scope 是指 Bean 的作用域,預設情況下是單例模式,這也是使用最多的一種方式;多例模式,即每次從 BeanFactory 中擷取 Bean 都會建立一個新的 Bean。Request、Session、Global-session 是在 Web 服務中使用的 Scope。
●Request 每次請求都建立一個執行個體;
●Session 是在一個會話周期内保證隻有一個執行個體;
●Global-session 在 5.x 版本中已經不再使用,同時增加了 Application 和 Websocket 兩種Scope,分别保證在一個 ServletContext 與一個 WebSocket 中隻建立一個執行個體。
還可以了解一下 Spring 的事件機制,知道 Spring 定義的五種标準事件,了解如何自定義事件和實作對應的 ApplicationListener 來處理自定義事件。
應用
下面來看 Spring 應用相關的知識點,如下圖所示。
首先要熟練掌握常用注解的使用。
1.類型類的注解,包括 Controller、Service 等,可以重點了解一下 Component 和 Bean 注解的差別:
a.Component 注解在類上使用表明這個類是個元件類,需要 Spring 為這個類建立 Bean。
[email protected] 注解使用在方法上,告訴 Spring 這個方法将會傳回一個 Bean 對象,需要把傳回的對象注冊到 Spring 的應用上下文中。
2.設定類注解可以重點了解 @Autowire 和 @Qualifier 以及 byType、byName 等不同的自動裝配機制。
3.Web 類主要以了解為主,關注 @RequestMapping、@GetMapping、@PostMapping 等路徑比對注解,以及 @PathVariable、@RequestParam 等參數擷取注解。
4.功能類的注解,包括 @ImportResource 引用配置、@ComponentScan 注解自動掃描、@Transactional 事務注解等等,這裡不一一介紹了。
如上圖右邊所示,Spring 應用部分,還需要了解配置 Spring 的幾種方式:XML 檔案配置、注解配置和使用 API 進行配置。
自動裝配機制需要了解按類型比對進行自動裝配,按 Bean 名稱進行自動裝配,構造器中的自動裝配和自動檢測等主要的四種方式。
最後還可以了解一下 List、Set、Map 等集合類屬性的配置方式以及内部 Bean 的使用。
Context 初始化流程
如下圖所示,左側是三種類型的 Context:
●XML 配置方式的 Context;
●Spring Boot 的 Context;
●Web 服務的 Context。
不論哪種 Context,建立後都會調用到 AbstractApplicationContext 類的 refresh 方法,流程如下。
1.首先對重新整理進行準備,包括設定開始時間、設定激活狀态、初始化 Context 環境中的占位符,這個動作根據子類的需求由子類來執行,然後驗證是否缺失必要的 properties。
2.重新整理并獲得内部的 Bean Factory。
3.對 BeanFactory 進行準備工作,比如設定類加載器和後置處理器、配置不進行自動裝配的類型、注冊預設的環境 Bean。
4.為 Context 的子類提供後置處理 BeanFactory 的擴充能力。如果子類想在 Bean 定義加載完成後,開始初始化上下文之前做一些特殊邏輯,可以複寫這個方法。
5.執行 Context 中注冊的 Bean Factory 字尾處理器。這裡有兩種後置處理器,一種是可以注冊 Bean 的字尾處理器,另一種是針對 BeanFactory 進行處理的後置處理器。執行的順序是,先按優先級執行可注冊 Bean 的處理器,在按優先級執行針對 BeanFactory的處理器。對 Spring Boot 來說,這一步會進行注解 Bean Definition 的解析。流程如圖右側所示,由 ConfigurationClassPostProcessor 觸發、由 ClassPathBeanDefinitionScanner 解析并注冊到 BeanFactory。
6.按優先級順序在 BeanFactory 中注冊 Bean的字尾處理器,Bean 後置處理器可以在 Bean 初始化前、後執行處理。
7.初始化消息源,消息源用來支援消息的國際化。
8.初始化應用事件廣播器。事件廣播器用來向 ApplicationListener 通知各種應用産生的事件,是一個标準的觀察者模式。
9.是留給子類的擴充步驟,用來讓特定的 Context 子類初始化其他的 Bean。
10.把實作了 ApplicationListener 的 Bean 注冊到事件廣播器,并對廣播器中的早期未廣播事件進行通知。
11.當機所有 Bean 描述資訊的修改,執行個體化非延遲加載的單例 Bean。
12.完成上下文的重新整理工作,調用 LifecycleProcessor 的 onFresh() 方法以及釋出 ContextRefreshedEvent 事件。
13.在 finally 中,執行第十三步,重置公共的緩存,比如 ReflectionUtils 中的緩存、 AnnotationUtils 中的緩存等等;
至此,Spring 的 Context 初始化完成。由于篇幅和時間的關系,這裡介紹了最主要的主流程,建議課後閱讀源碼來複習這個知識點,補全細節。
Bean 生命周期
面試中經常問到 Bean 的生命周期,如下圖,我們先看綠色的部分,Bean 的建立過程。
1.調用 Bean 的構造方法建立 Bean;
2.通過反射調用 setter 方法進行屬性的依賴注入;
3.如果實作 BeanNameAware 接口的話,會設定 Bean 的 name;
4.如果實作了 BeanFactoryAware,會把 BeanFactory 設定給 Bean;
5.如果實作了 ApplicationContextAware,會給 Bean 設定 ApplictionContext;
6.如果實作了 BeanPostProcessor 接口,則執行前置處理方法;
7.實作了 InitializingBean 接口的話,執行 afterPropertiesSet 方法;
8.執行自定義的 init 方法;
9.執行 BeanPostProcessor 接口的後置處理方法。
以上就完成了 Bean 的建立過程。而在使用完 Bean 需要銷毀時,會先執行 DisposableBean 接口的 destroy 方法,然後在執行自定義的 destroy 方法。這部分也建議閱讀源碼加深了解。
擴充接口
在對 Spring 進行定制化功能擴充時,可以選擇一些擴充點,如下圖所示。
●BeanFactoryPostProcessor 是 BeanFactory 後置處理器,支援在 BeanFactory 标準初始化完成後,對 BeanFactory 進行一些額外處理。講 Context 初始化流程時介紹過,這時所有的 Bean 的描述資訊已經加載完畢,但是還沒有進行 Bean 初始化。例如前面提到的 PropertyPlaceholderConfigurer,就是在這個擴充點上對 Bean 屬性中的占位符進行替換。
●BeanDefinitionRegistryPostProcessor,它擴充自BeanFactoryPostProcessor,在執行 BeanFactoryPostProcessor 的功能前,提供了可以添加 Bean Definition 的能力,允許在初始化一般 Bean 前,注冊額外的 Bean。例如可以在這裡根據 Bean 的 Scope 建立一個新的代理 Bean。
●BeanPostProcessor,提供了在 Bean 初始化之前和之後插入自定義邏輯的能力。與 BeanFactoryPostProcessor 的差別是處理的對象不同,BeanFactoryPostProcessor 是對 BeanFactory 進行處理,BeanPostProcessor 是對 Bean 進行處理。
上面這三個擴充點,可以通過實作 Ordered 和PriorityOrdered 接口來指定執行順序。實作 PriorityOrdered 接口的 processor 會先于實作 Ordered 接口的執行。
●ApplicationContextAware,可以獲得 ApplicationContext 及其中的 Bean,當需要在代碼中動态擷取 Bean 時,可以通過實作這個接口來實作。
●InitializingBean,可以在 Bean 初始化完成,所有屬性設定完成後執行特定邏輯,例如對自動裝配對屬性進行驗證等。
●DisposableBean,用于在 Bean 被銷毀前執行特定的邏輯,例如做一些回收工作等。
●ApplicationListener,用來監聽 Spring 的标準應用事件或者自定義事件。
Spring Boot
下面來看 Spring Boot 相關的知識點,如下圖所示。
首先是 Spring Boot 啟動流程的主要步驟:
1.要配置 Environment。
2.準備 Context 上下文,包括執行 ApplicationContext 的後置處理、初始化 Initializer、通知Listener 處理 ContextPrepared 和 ContextLoaded 事件。
3.執行 refreshContext,也就是前面介紹過的 AbstractApplicationContext 類的 refresh 方法。
然後要知道在 Spring Boot 中有兩種上下文,一種是 bootstrap, 另外一種是 application。其中,bootstrap 是應用程式的父上下文,會先于 applicaton 加載。bootstrap 主要用于從額外的資源來加載配置資訊,還可以在本地外部配置檔案中解密屬性。bootstrap 裡面的屬性會優先加載,預設也不能被本地相同配置覆寫。
再來看 Spring Boot 的注解。
需要知道 @SpringBootApplication 包含了 @ComponentScan、@EnableAutoConfiguration、@SpringBootConfiguration 三個注解,而 @SpringBootConfiguration 注解包含了 @Configuration 注解。也就是 Spring Boot 的自動配置功能。@Conditional 注解就是控制自動配置的生效條件的注解,例如 Bean 或 Class 存在、不存在時進行配置,當滿足條件時進行配置等。
最後,了解一下 Spring Boot 的幾個特色子產品。
●Starter 是 Spring Boot 提供的無縫內建功能的一種方式,使用某個功能時開發者不需要關注各種依賴庫的處理,不需要具體的配置資訊,由 Spring Boot 自動配置進行 Bean的建立。例如需要使用 Web 功能時,隻需要在依賴中引入 Spring-boot-starter-web 即可。
●Actuator 是用來對應用程式進行監視和管理,通過 RESTful API 請求來監管、審計、收集應用的運作情況。
●DevTools 提供了一系列開發工具的支援,來提高開發效率。例如熱部署能力等。
●CLI 就是指令行接口,是一個指令行工具,支援使用 Groovy 腳本,可以快速搭建 Spring 原型項目。