一文入門Spring

一、Spring快速入門程序

接下來先看一個最簡單的Spring項目構建過程

  1. 編寫對象類(HelloWorld.java)
    在這裏插入圖片描述

  2. 根據對象類創建bean配置文件(Beans.xml)

  • 這個文件需要在 src 目錄下創建。Beans.xml 用於給不同的 bean 分配唯一的 ID,並且控制不同值的對象的創建,而不會影響 Spring 的任何源文件。
  • 通過bean,將helloworld這個實例的name屬性賦值爲message,value賦值爲Hello World!
    在這裏插入圖片描述
  1. 創建啓動程序(MainApp.java)
  • 第一步是我們使用框架 API ClassPathXmlApplicationContext() 來創建應用程序的上下文。
  • 第二步是使用已創建的上下文的 getBean() 方法來獲得所需的 bean。
    在這裏插入圖片描述

二、Spring IoC容器

容器

先介紹下IoC容器是什麼

IoC容器 Spring 容器是 Spring 框架的核心。容器將創建對象,把它們連接在一起,配置它們,並管理他們的整個生命週期從創建到銷燬。Spring容器使用依賴注入(DI)來管理組成一個應用程序的組件。這些對象被稱爲 Spring Beans。

通過閱讀配置元數據(Beans.xml)提供的指令,容器知道對哪些對象進行實例化,配置和組裝。

上面的代碼中,context對象加載Beans.xml配置文件,通過getBean(“helloword”)這個函數獲得id=“helloword”的Beans實例。

IOC 容器具有依賴注入功能的容器,它可以創建對象,IOC
容器負責實例化、定位、配置應用程序中的對象及建立這些對象間的依賴。通常new一個實例,控制權由程序員控制,而"控制反轉"是指new實例工作不由程序員來做而是交給Spring容器來做。在Spring中BeanFactory是IOC容器的實際代表者。
在這裏插入圖片描述

  • 很容易發現,obj是通過getBean(“helloword”)獲得一個對象的,而不是之前new一個對象獲得。name\value這些屬性字段也不再像之前那樣通過new Helloword(“hello”, “world”)這種通過構造函數賦值獲得。在"控制反轉"之後,Spring容器通過bean配置獲得了一個對象。

  • 簡而言之,過去由程序員通過new對象(構造、set方法)形式轉變爲容器通過依賴注入(DI)類(bean配置)獲得。

  • 容器有以下兩類
    在這裏插入圖片描述

Spring 的 BeanFactory 容器

先來看看BeanFactory的定義

這是一個最簡單的容器,它主要的功能是爲依賴注入 (DI) 提供支持,這個容器接口在 org.springframework.beans.factory.BeanFactor 中被定義。BeanFactory 和相關的接口,比如BeanFactoryAware、DisposableBean、InitializingBean,仍舊保留在 Spring 中,主要目的是向後兼容已經存在的和那些 Spring 整合在一起的第三方框架。

在 Spring 中,有大量對 BeanFactory 接口的實現。其中,最常被使用的是 XmlBeanFactory 類。這個容器從一個XML 文件中讀取配置元數據,由這些元數據來生成一個被配置化的系統或者應用。

在資源寶貴的移動設備或者基於 applet 的應用當中, BeanFactory 會被優先選擇。否則,一般使用的是ApplicationContext,除非你有更好的理由選擇 BeanFactory。

來看看入口函數中怎麼使用容器的
在這裏插入圖片描述
在主程序當中,我們需要注意以下兩點:

  • 第一步利用框架提供的 XmlBeanFactory() API 去生成工廠 bean 以及利用 ClassPathResource() API 去加載在路徑 CLASSPATH 下可用的 bean 配置文件。XmlBeanFactory() API 負責創建並初始化所有的對象,即在配置文件中提到的 bean。

  • 第二步利用第一步生成的 bean 工廠對象的 getBean() 方法得到所需要的 bean。 這個方法通過配置文件中的 bean ID 來返回一個真正的對象,該對象最後可以用於實際的對象。一旦得到這個對象,你就可以利用這個對象來調用任何方法。

Spring ApplicationContext 容器

Application Context 是 BeanFactory 的子接口,也被成爲 Spring 上下文。
Application Context 是 spring 中較高級的容器。和 BeanFactory 類似,它可以加載配置文件中定義的 bean,將所有的 bean 集中在一起,當有請求的時候分配 bean。 這個容器在 org.springframework.context.ApplicationContext interface 接口中定義。

和BeanFactory的區別

它增加了企業所需要的功能,比如,從屬性文件中解析文本信息和將事件傳遞給所指定的監聽器。 ApplicationContext 包含
BeanFactory 所有的功能,一般情況下,相對於BeanFactory,ApplicationContext會更加優秀。當然,BeanFactory 仍可以在輕量級應用中使用,比如移動設備或者基於 applet 的應用程序。

最常被使用的 ApplicationContext 接口實現:

  • FileSystemXmlApplicationContext:該容器從 XML 文件中加載已被定義的 bean。在這裏,你需要提供給構造器 XML 文件的完整路徑。
  • ClassPathXmlApplicationContext:該容器從 XML 文件中加載已被定義的 bean。在這裏,你不需要提供 XML 文件的完整路徑,只需正確配置 CLASSPATH 環境變量即可,因爲,容器會從 CLASSPATH 中搜索 bean 配置文件。
  • WebXmlApplicationContext:該容器會在一個 web 應用程序的範圍內加載在 XML 文件中已被定義的 bean。

使用FileSystemXmlApplicationContext例子:
在這裏插入圖片描述

  • 第一步生成工廠對象。加載完指定路徑下 bean 配置文件後,利用框架提供的 FileSystemXmlApplicationContext API 去生成工廠 bean。FileSystemXmlApplicationContext 負責生成和初始化所有的對象,比如,所有在 XML bean 配置文件中的 bean。

  • 第二步利用第一步生成的上下文中的 getBean() 方法得到所需要的 bean。 這個方法通過配置文件中的 bean ID 來返回一個真正的對象。一旦得到這個對象,就可以利用這個對象來調用任何方法。

在第一章中用的是ClassPathXmlApplicationContext,在這一節中用的是FileSystemXmlApplicationContext,在之後章節使用WebXmlApplicationContext

Bean

Spring Bean 定義

這部分講解如何編寫bean.xml配置文件。

被稱作 bean 的對象是構成應用程序的支柱也是由 Spring IoC 容器管理的。bean 是一個被實例化,組裝,並通過 Spring IoC 容器所管理的對象。這些 bean 是由用容器提供的配置元數據創建的,例如,已經在先前章節看到的,在 XML 的表單中的 定義。

  1. bean 定義包含稱爲配置元數據的信息,下述容器也需要知道配置元數據:
  • 如何創建一個 bean
  • bean 的生命週期的詳細信息
  • bean 的依賴關係

在這裏插入圖片描述

  1. bean與spring 容器之間的關係
    在這裏插入圖片描述

3.Spring IoC 容器完全由實際編寫的配置元數據的格式解耦。有下面三個重要的方法把配置元數據提供給 Spring 容器:

  • 基於 XML 的配置文件(Beans.xml)
  • 基於註解的配置(@Autowrite)
  • 基於 Java 的配置(@Configuration)

Spring Bean 作用域

當在 Spring 中定義一個 bean 時,你必須聲明該 bean 的作用域的選項。例如,爲了強制 Spring

在每次需要時都產生一個新的 bean 實例,你應該聲明 bean 的作用域的屬性爲 prototype。同理,如果你想讓 Spring 在每次需要時都返回同一個bean實例,你應該聲明 bean 的作用域的屬性爲 singleton。

Spring 框架支持以下五個作用域,分別爲singleton、prototype、request、session和global session,5種作用域說明如下所示
注意,如果你使用 web-aware ApplicationContext 時,其中三個是可用的。
在這裏插入圖片描述

Singleon作用域
singleton 是默認的作用域。Singleton是單例類型,就是在創建起容器時就同時自動創建了一個bean的對象,不管你是否使用,他都存在了。Spring IoC容器只會創建該bean定義的唯一實例,只要id與該bean定義相匹配,則只會返回bean的同一實例。

prototype 作用域
Prototype作用域的bean會導致在每次對該bean請求(將其注入到另一個bean中,或者以程序的方式調用容器的getBean()方法)時都會創建一個新的bean實例。Prototype是原型類型,它在我們創建容器的時候並沒有實例化,而是當我們獲取bean的時候纔會去創建一個對象,而且我們每次獲取到的對象都不是同一個對象。根據經驗,對有狀態的bean應該使用prototype作用域,而對無狀態的bean則應該使用singleton作用域。

在這裏插入圖片描述

Spring Bean 生命週期

Bean的生命週期可以表達爲:Bean的定義——Bean的初始化——Bean的使用——Bean的銷燬
聲明帶有 init-method 和/或 destroy-method 參數的 。init-method 屬性指定一個方法,在實例化 bean 時,立即調用該方法。同樣,destroy-method 指定一個方法,只有從容器中移除 bean 之後,才能調用該方法。

舉個栗子:
對象類文件
在這裏插入圖片描述

Beans.xml 文件:
在這裏插入圖片描述
這裏使用了是AbstractApplicationContext,它可以調用關閉 hook 的 registerShutdownHook() 方法。它將確保正常關閉,並且調用相關的 destroy 方法。
在這裏插入圖片描述
程序輸出
在這裏插入圖片描述

如果你有太多具有相同名稱的初始化或者銷燬方法的 Bean,那麼你不需要在每一個 bean 上聲明初始化方法和銷燬方法。框架使用 元素中的 default-init-method 和 default-destroy-method 屬性提供了靈活地配置這種情況
在這裏插入圖片描述

三、Spring 依賴注入

每個基於應用程序的 java 都有幾個對象,這些對象一起工作來呈現出終端用戶所看到的工作的應用程序。當編寫一個複雜的 Java 應用程序時,應用程序類應該儘可能獨立於其他 Java 類來增加這些類重用的可能性,並且在做單元測試時,測試獨立於其他類的獨立性。依賴注入(或有時稱爲佈線)有助於把這些類粘合在一起,同時保持他們獨立。

過去要在一個對象中引用另一個對象是這麼寫的:
在這裏插入圖片描述
在控制反轉的場景中,我們反而會做這樣的事情:
在這裏插入圖片描述

在這裏,TextEditor 不應該擔心 SpellChecker 的實現。SpellChecker 將會獨立實現,並且在 TextEditor 實例化的時候將提供給 TextEditor,整個過程是由 Spring 框架的控制。

在這裏,我們已經從 TextEditor 中刪除了全面控制,並且把它保存到其他地方(即 XML 配置文件),且依賴關係(即 SpellChecker 類)通過類構造函數被注入到 TextEditor 類中。因此,控制流通過依賴注入(DI)已經“反轉”,因爲你已經有效地委託依賴關係到一些外部系統。

依賴注入的第二種方法是通過 TextEditor 類的 Setter 方法,我們將創建 SpellChecker 實例,該實例將被用於調用 setter 方法來初始化 TextEditor 的屬性。

DI 主要有兩種變體和下面的兩個子章將結合實例涵蓋它們
在這裏插入圖片描述

依賴注入有基於構造函數、基於setter函數注入形式

Spring 基於構造函數的依賴注入

首先舉個栗子:
一個依賴類文件 SpellChecker.java,被TextEditor類調用
在這裏插入圖片描述
TextEditor.java 文件的內容:
在這裏插入圖片描述
配置文件 Beans.xml 的內容,它有基於構造函數注入的配置:
在這裏插入圖片描述
以下是 MainApp.java 文件的內容:
在這裏插入圖片描述

  • 看到這大家也就明白了,首先IoC容器通過getBean獲得TestEditor類,實例化TestEditor的Bean時,發現有依賴類SpellCheck類,故需先實例化SpellCheck的bean,將其通過構造函數注入到TestEditor的Bean中,這裏使用的是constructor-arg ref="">來配置的(引用對象是ref,普通值爲value屬性)。相當於過去的new TestEditor(new SpellCheck())。

如果存在不止一個參數時,當把參數傳遞給構造函數時,可能會存在歧義。要解決這個問題,那麼構造函數的參數在 bean 定義中的順序就是把這些參數提供給適當的構造函數的順序就可以了
在這裏插入圖片描述
在這裏插入圖片描述

再檢查一下我們傳遞給構造函數不同類型的位置。考慮下面的類:
在這裏插入圖片描述
如果你使用 type 屬性顯式的指定了構造函數參數的類型,容器也可以使用與簡單類型匹配的類型。例如:
在這裏插入圖片描述
最後並且也是最好的傳遞構造函數參數的方式,使用 index 屬性來顯式的指定構造函數參數的索引。下面是基於索引爲 0 的例子,如下所示:

在這裏插入圖片描述
如果你想要向一個對象傳遞一個引用,你需要使用 標籤的 ref 屬性,如果你想要直接傳遞,那麼你應該使用如上所示的 value 屬性

Spring 基於setter函數的依賴注入

TextEditor.java 文件的內容:
構造
在這裏插入圖片描述
設值
在這裏插入圖片描述
要設置一個變量 spellChecker,我們使用 setSpellChecker() 方法,該方法與 Java POJO 類非常相似。

依賴類文件 SpellChecker.java
在這裏插入圖片描述

下面是配置文件 Beans.xml 的內容,該文件有基於設值函數注入的配置:
在這裏插入圖片描述
唯一的區別就是在基於構造函數注入中,我們使用的是〈bean〉標籤中的〈constructor-arg〉元素,而在基於設值函數的注入中,我們使用的是〈bean〉標籤中的〈property〉元素。

第二個你需要注意的點是,如果你要把一個引用傳遞給一個對象,那麼你需要使用 標籤的 ref 屬性,而如果你要直接傳遞一個值,那麼你應該使用 value 屬性。

使用 p-namespace 實現 XML 配置:
以帶有 標籤的標準 XML 配置文件爲例:
在這裏插入圖片描述
上述 XML 配置文件可以使用 p-namespace 以一種更簡潔的方式重寫,如下所示:
在這裏插入圖片描述

Spring 注入內部 Beans

基於設值函數的依賴注入還可以有另一種寫法。正如你所知道的 Java 內部類是在其他類的範圍內被定義的,同理,inner beans 是在其他 bean 的範圍內定義的 bean。因此在 或 元素內 元素被稱爲內部bean,如下所示。

TextEditor.java 文件的內容:
在這裏插入圖片描述
依賴的類文件 SpellChecker.java 內容:
在這裏插入圖片描述
使用內部 bean 爲基於 setter 注入進行配置的配置文件 Beans.xml 文件:
在這裏插入圖片描述
之前寫法將spellChecker類分出來
在這裏插入圖片描述

Spring注入集合

如果你想傳遞多個值,如 Java Collection 類型 List、Set、Map 和 Properties,應該怎麼做呢。爲了處理這種情況,Spring 提供了四種類型的集合的配置元素,如下所示:
在這裏插入圖片描述
栗子:
JavaCollection.java 文件的內容:
在這裏插入圖片描述
配置所有類型的集合的配置文件 Beans.xml 文件:
在這裏插入圖片描述
在這裏插入圖片描述
MainApp.java內容
在這裏插入圖片描述

注入 Bean 引用
下面的 Bean 定義將幫助你理解如何注入 bean 的引用作爲集合的元素。甚至你可以將引用和值混合在一起,如下所示:

在這裏插入圖片描述
在這裏插入圖片描述
爲了使用上面的 bean 定義,你需要定義 setter 方法,它們應該也能夠是用這種方式來處理引用

在這裏插入圖片描述

四、Spring Beans 自動裝配

Spring 容器可以在不使用和 元素的情況下自動裝配相互協作的 bean 之間的關係,這有助於減少編寫一個大的基於 Spring 的應用程序的 XML 配置的數量。

自動裝配模式
你可以使用元素的 autowire 屬性爲一個 bean 定義指定自動裝配模式。
在這裏插入圖片描述

自動裝配的侷限性
在這裏插入圖片描述

Spring 自動裝配 byName

這種模式由屬性名稱指定自動裝配。Spring 容器看作 beans,在 XML 配置文件中 beans 的 auto-wire 屬性設置爲 byName。然後,它嘗試將它的屬性與配置文件中定義爲相同名稱的 beans 進行匹配和連接。如果找到匹配項,它將注入這些 beans,否則,它將拋出異常。

例如,在配置文件中,如果一個 bean 定義設置爲自動裝配 byName,並且它包含 spellChecker 屬性(即,它有一個setSpellChecker(…) 方法),那麼 Spring 就會查找定義名爲 spellChecker 的bean,並且用它來設置這個屬性。你仍然可以使用 標籤連接其餘的屬性。下面的例子將說明這個概念。

TextEditor.java 文件的內容:
在這裏插入圖片描述
依賴類文件 SpellChecker.java 的內容:
在這裏插入圖片描述
下面是 MainApp.java 文件的內容:
在這裏插入圖片描述
下面是在正常情況下的配置文件 Beans.xml 文件:
在這裏插入圖片描述
使用自動裝配 “byName”,那麼你的 XML 配置文件將成爲如下:
在這裏插入圖片描述
可以發現使用autowire 與不使用的區別在於是否需要顯示引用。 beans 的 auto-wire 屬性設置爲 byName後,嘗試將它的屬性與配置文件中定義爲相同名稱的 beans 進行匹配和連接。

Spring 自動裝配 byType

這種模式由屬性類型指定自動裝配。Spring 容器看作 beans,在 XML 配置文件中 beans 的 autowire 屬性設置爲byType。然後,如果它的 type 恰好與配置文件中 beans名稱中的一個相匹配,它將嘗試匹配和連接它的屬性。如果找到匹配項,它將注入這些 beans,否則,它將拋出異常。

例如,在配置文件中,如果一個 bean 定義設置爲自動裝配 byType,並且它包含 SpellChecker 類型的spellChecker 屬性,那麼 Spring 就會查找定義名爲 SpellChecker 的bean,並且用它來設置這個屬性。你仍然可以使用 標籤連接其餘屬性。下面的例子將說明這個概念,你會發現和上面的例子沒有什麼區別,除了 XML 配置文件已經被改變。

普通配置
在這裏插入圖片描述
自動裝配 “byType”,那麼你的 XML 配置文件將成爲如下:
在這裏插入圖片描述

Spring 由構造函數自動裝配

前兩種都是基於設值函數依賴注入的,由構造函數自動裝配基於構造函數依賴注入。

這種模式與 byType 非常相似,但它應用於構造器參數。Spring 容器看作 beans,在 XML 配置文件中 beans 的autowire 屬性設置爲 constructor。然後,它嘗試把它的構造函數的參數與配置文件中 beans名稱中的一個進行匹配和連線。如果找到匹配項,它會注入這些 bean,否則,它會拋出異常。

例如,在配置文件中,如果一個 bean 定義設置爲通過構造函數自動裝配,而且它有一個帶有 SpellChecker 類型的參數之一的構造函數,那麼 Spring 就會查找定義名爲 SpellChecker 的 bean,並用它來設置構造函數的參數。你仍然可以使用 標籤連接其餘屬性。下面的例子將說明這個概念。

TextEditor.java 文件的內容:
在這裏插入圖片描述
依賴類文件 SpellChecker.java 的內容:
在這裏插入圖片描述
正常情況下的配置文件 Beans.xml 文件:
在這裏插入圖片描述
使用自動裝配 “by constructor”,那麼你的 XML 配置文件將成爲如下:
在這裏插入圖片描述

五、Spring 基於註解的配置

常用註解
在這裏插入圖片描述

Spring @Required 註釋

@Required 註釋應用於 bean 屬性的 setter 方法,它表明受影響的 bean 屬性在配置時必須放在 XML配置文件中,否則容器就會拋出一BeanInitializationException 異常。下面顯示的是一個使用 @Required註釋的示例。
Student.java 文件的內容:
在這裏插入圖片描述

MainApp.java 文件的內容:
在這裏插入圖片描述
配置文件 Beans.xml: 文件的內容:(缺少age配置)
在這裏插入圖片描述
引起 BeanInitializationException 異常,並且會輸出一下錯誤信息和其他日誌消息:
在這裏插入圖片描述
“age” 屬性中刪除了註釋,將正常
在這裏插入圖片描述

Spring @Autowired 註釋

@Autowired 註釋對在哪裏和如何完成自動連接提供了更多的細微的控制。
@Autowired 註釋可以在 setter 方法中被用於自動連接 bean,就像 @Autowired 註釋,容器,一個屬性或者任意命名的可能帶有多個參數的方法。

Setter 方法中的 @Autowired
你可以在 XML 文件中的 setter 方法中使用 @Autowired 註釋來除去 元素。當 Spring遇到一個在 setter 方法中使用的 @Autowired 註釋,它會在方法中視圖執行 byType 自動連接。

TextEditor.java 文件的內容:
在這裏插入圖片描述
SpellChecker.java 的內容:
在這裏插入圖片描述
配置文件 Beans.xml:
在這裏插入圖片描述

屬性中的 @Autowired
在屬性上註解@Autowired。Spring 會將這些傳遞過來的值或者引用自動分配給那些屬性。
在這裏插入圖片描述
配置文件 Beans.xml:
在這裏插入圖片描述

構造函數中的 @Autowired

在構造函數中使用 @Autowired。一個構造函數 @Autowired 說明當創建 bean 時,即使在 XML 文件中沒有使用 元素配置 bean ,構造函數也會被自動連接。
在這裏插入圖片描述
配置文件 Beans.xml:
在這裏插入圖片描述

@Autowired 的(required=false)選項

默認情況下,@Autowired 註釋意味着依賴是必須的,它類似於 @Required 註釋,然而,你可以使用 @Autowired 的 (required=false) 選項關閉默認行爲。

即使你不爲 age 屬性傳遞任何參數,下面的示例也會成功運行,但是對於 name 屬性則需要一個參數。你可以自己嘗試一下這個示例,因爲除了只有 Student.java 文件被修改以外,它和 @Required 註釋示例是相似的。

在這裏插入圖片描述

Spring @Qualifier 註釋

可能會有這樣一種情況,當你創建多個具有相同類型的 bean 時,並且想要用一個屬性只爲它們其中的一個進行裝配,在這種情況下,你可以使用 @Qualifier 註釋和 @Autowired 註釋通過指定哪一個真正的 bean 將會被裝配來消除混亂。下面顯示的是使用 @Qualifier 註釋的一個示例。

Student.java 文件的內容:
在這裏插入圖片描述
Profile.java 文件的內容:
在這裏插入圖片描述
MainApp.java 文件的內容:
在這裏插入圖片描述
配置文件 Beans.xml 的示例:
在這裏插入圖片描述
使用屬性@Autowired註解,故Profile的bean中不需要寫Student的配置。由於@Qualifier(“student1”)註解表明注入到Profile對象的是student1。

六、基於 Java 的配置

基於 Java 的配置選項,可以使你在不用配置 XML 的情況下編寫大多數的 Spring,但是一些有幫助的基於 Java 的註解

@Configuration 和 @Bean 註解

帶有 @Configuration 的註解類表示這個類可以使用 Spring IoC 容器作爲 bean 定義的來源。@Bean 註解告訴 Spring,一個帶有 @Bean 的註解方法將返回一個對象,該對象應該被註冊爲在 Spring 應用程序上下文中的 bean。最簡單可行的 @Configuration 類如下所示

在這裏插入圖片描述
之前的章節都在介紹依賴注入的內容,通過bean配置硬編碼的爲一些屬性對象賦值,但這樣做明細不符合開發的合理性,很多屬性我們可能都是動態獲得的,從數據庫中讀取或者前端返回。@Configuration 在某個類中註解,比如Controller類,表示對象的值可以從該類中動態獲取;那麼比如動態獲取的是某個對象,使用@Bean註解即可達到和在xml文件中配置bean的目的。

在這裏插入圖片描述

  • 在這裏,帶有 @Bean 註解的方法名稱作爲 bean 的 ID,它創建並返回實際的 bean。你的配置類可以聲明多個 @Bean。

一旦定義了配置類,你就可以使用 AnnotationConfigApplicationContext 來加載並把他們提供給 Spring 容器。
在這裏插入圖片描述
對比下之前的Main
在這裏插入圖片描述
可以加載各種配置類,如下所示:
在這裏插入圖片描述
舉個栗子
HelloWorld.java 文件的內容:
在這裏插入圖片描述

HelloWorldConfig.java 文件的內容: 在這裏插入圖片描述
下面是 MainApp.java 文件的內容:
在這裏插入圖片描述
注入 Bean 的依賴性
@Beans 依賴對方時,表達這種依賴性非常簡單,只要有一個 bean 方法調用另一個,如下所示:
在這裏插入圖片描述
對比之前xml配置
在這裏插入圖片描述
再來個栗子:
TextEditor.java 文件的內容:
在這裏插入圖片描述
依賴的類文件 SpellChecker.java 的內容:
在這裏插入圖片描述
TextEditorConfig.java 文件的內容:
在這裏插入圖片描述
MainApp.java 文件的內容:
在這裏插入圖片描述
生命週期回調
@Bean 註解支持指定任意的初始化和銷燬的回調方法,就像在 bean 元素中 Spring 的 XML 的初始化方法和銷燬方法的屬性:
在這裏插入圖片描述
指定 Bean 的範圍:

默認範圍是單實例,但是你可以重寫帶有 @Scope 註解的該方法,如下所示:

在這裏插入圖片描述

@Import 註解:

@import 註解允許從另一個配置類中加載 @Bean 定義。考慮 ConfigA 類,如下所示:
在這裏插入圖片描述
當實例化上下文時,不需要同時指定 ConfigA.class 和 ConfigB.class,只有 ConfigB 類需要提供,如下所示:
在這裏插入圖片描述

七、Spring 中的事件處理

你已經看到了在所有章節中 Spring 的核心是 ApplicationContext,它負責管理 beans 的完整生命週期。當加載 beans 時,ApplicationContext 發佈某些類型的事件。例如,當上下文啓動時,ContextStartedEvent 發佈,當上下文停止時,ContextStoppedEvent 發佈

通過 ApplicationEvent 類和 ApplicationListener 接口來提供在 ApplicationContext 中處理事件。如果一個 bean 實現 ApplicationListener,那麼每次 ApplicationEvent 被髮布到 ApplicationContext 上,那個 bean 會被通知。

在這裏插入圖片描述
由於 Spring 的事件處理是單線程的,所以如果一個事件被髮布,直至並且除非所有的接收者得到的該消息,該進程被阻塞並且流程將不會繼續。因此,如果事件處理被使用,在設計應用程序時應注意。

監聽上下文事件

爲了監聽上下文事件,一個 bean 應該實現只有一個方法 onApplicationEvent() 的 ApplicationListener 接口。因此,我們寫一個例子來看看事件是如何傳播的,以及如何可以用代碼來執行基於某些事件所需的任務。

HelloWorld.java 文件的內容:
在這裏插入圖片描述
CStartEventHandler.java 文件的內容:
在這裏插入圖片描述
CStopEventHandler.java 文件的內容:
在這裏插入圖片描述
MainApp.java 文件的內容:
在這裏插入圖片描述
配置文件 Beans.xml 文件:
在這裏插入圖片描述

八、Spring 框架的 AOP

Spring 框架的一個關鍵組件是面向切面的編程(AOP)框架。面向切面的編程需要把程序邏輯分解成不同的部分稱爲所謂的關注點。跨一個應用程序的多個點的功能被稱爲橫切關注點,這些橫切關注點在概念上獨立於應用程序的業務邏輯。有各種各樣的常見的很好的方面的例子,如日誌記錄、審計、聲明式事務、安全性和緩存等。

AOP 術語
在我們開始使用 AOP 工作之前,讓我們熟悉一下 AOP 概念和術語。這些術語並不特定於 Spring,而是與 AOP 有關的。
在這裏插入圖片描述
通知的類型
Spring 方面可以使用下面提到的五種通知工作:
在這裏插入圖片描述
實現自定義方面
Spring 支持 @AspectJ annotation style 的方法和基於模式的方法來實現自定義方面。這兩種方法已經在下面兩個子節進行了詳細解釋。
在這裏插入圖片描述

Spring 中基於 AOP 的 XML架構

聲明一個 aspect
在這裏插入圖片描述
聲明一個Join Point
在這裏插入圖片描述
在這裏插入圖片描述
聲明Advice
可以使用 <aop:{ADVICE NAME}> 元素在一個 中聲明五個建議中的任何一個,如下所示:
在這裏插入圖片描述
你可以對不同的建議使用相同的 doRequiredTask 或者不同的方法。這些方法將會作爲 aspect 模塊的一部分來定義.

基於 AOP 的 XML 架構的示例
Logging.java 文件,aspect 模塊的一個示例,它定義了在各個點調用的方法。
在這裏插入圖片描述
在這裏插入圖片描述
Student.java 文件的內容:
在這裏插入圖片描述
MainApp.java 文件的內容:
在這裏插入圖片描述
配置文件 Beans.xml:
在這裏插入圖片描述
在這裏插入圖片描述

Spring 中基於 AOP 的 @Aspect

Logging.java 文件的內容
在這裏插入圖片描述
在這裏插入圖片描述
配置文件 Beans.xml:
在這裏插入圖片描述
Student.java 文件的內容:
在這裏插入圖片描述
MainApp.java 文件的內容:
在這裏插入圖片描述

九、Spring JDBC 框架

JdbcTemplate 類

JdbcTemplate 類執行 SQL 查詢、更新語句和存儲過程調用,執行迭代結果集和提取返回參數值。它也捕獲 JDBC 異常並轉換它們到 org.springframework.dao 包中定義的通用類、更多的信息、異常層次結構。
JdbcTemplate 類的實例是線程安全配置的。所以你可以配置 JdbcTemplate 的單個實例,然後將這個共享的引用安全地注入到多個 DAOs 中。
使用 JdbcTemplate 類時常見的做法是在你的 Spring 配置文件中配置數據源,然後共享數據源 bean 依賴注入到 DAO 類中,並在數據源的設值函數中創建了 JdbcTemplate。

提供一個數據源到 JdbcTemplate 中,所以它可以配置本身來獲得數據庫訪問。你可以在 XML 文件中配置數據源,其中一段代碼如下所示:
在這裏插入圖片描述
數據訪問對象(DAO)

DAO 代表常用的數據庫交互的數據訪問對象。DAOs 提供一種方法來讀取數據並將數據寫入到數據庫中,它們應該通過一個接口顯示此功能,應用程序的其餘部分將訪問它們。
在 Spring 中,數據訪問對象(DAO)支持很容易用統一的方法使用數據訪問技術,如 JDBC、Hibernate、JPA 或者 JDO。

執行 SQL 語句
jdbcTemplateObject.queryForObject(SQL, 參數, 返回類型);
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
執行 DDL 語句
可以使用 jdbcTemplate 中的 execute(…) 方法來執行任何 SQL 語句或 DDL 語句。下面是一個使用 CREATE 語句創建一個表的示例:
在這裏插入圖片描述
示例
Student.java 文件的內容:
在這裏插入圖片描述
StudentMapper.java 文件的內容:
在這裏插入圖片描述
數據訪問對象接口文件 StudentDAO.java 的內容:
在這裏插入圖片描述
在這裏插入圖片描述
爲定義的 DAO 接口 StudentDAO 的實現類文件 StudentJDBCTemplate.java:

在這裏插入圖片描述
配置文件 Beans.xml 的內容:
在這裏插入圖片描述

MainApp.java 文件的內容:
在這裏插入圖片描述

十、Spring 事務管理

一個數據庫事務是一個被視爲單一的工作單元的操作序列。這些操作應該要麼完整地執行,要麼完全不執行。事務管理是一個重要組成部分,RDBMS 面向企業應用程序,以確保數據完整性和一致性。事務的概念可以描述爲具有以下四個關鍵屬性說成是 ACID

一個真正的 RDBMS 數據庫系統將爲每個事務保證所有的四個屬性。使用 SQL 發佈到數據庫中的事務的簡單視圖如下:

  • 使用 begin transaction 命令開始事務。
  • 使用 SQL 查詢語句執行各種刪除、更新或插入操作。
  • 如果所有的操作都成功,則執行提交操作,否則回滾所有操作

Spring 框架在不同的底層事務管理 APIs 的頂部提供了一個抽象層。Spring 的事務支持旨在通過添加事務能力到 POJOs 來提供給 EJB 事務一個選擇方案。Spring 支持編程式和聲明式事務管理。EJBs 需要一個應用程序服務器,但 Spring 事務管理可以在不需要應用程序服務器的情況下實現。

局部事物 vs. 全局事務

  • 局部事務是特定於一個單一的事務資源,如一個 JDBC 連接,而全局事務可以跨多個事務資源事務,如在一個分佈式系統中的事務。

  • 局部事務管理在一個集中的計算環境中是有用的,該計算環境中應用程序組件和資源位於一個單位點,而事務管理只涉及到一個運行在一個單一機器中的本地數據管理器。局部事務更容易實現。

  • 全局事務管理需要在分佈式計算環境中,所有的資源都分佈在多個系統中。在這種情況下事務管理需要同時在局部和全局範圍內進行。分佈式或全局事務跨多個系統執行,它的執行需要全局事務管理系統和所有相關係統的局部數據管理人員之間的協調。

編程式 vs. 聲明式
Spring 支持兩種類型的事務管理:

  • 編程式事務管理 :這意味着你在編程的幫助下有管理事務。這給了你極大的靈活性,但卻很難維護。

  • 聲明式事務管理 :這意味着你從業務代碼中分離事務管理。你僅僅使用註釋或 XML 配置來管理事務。

  • 聲明式事務管理比編程式事務管理更可取,儘管它不如編程式事務管理靈活,但它允許你通過代碼控制事務。但作爲一種橫切關注點,聲明式事務管理可以使用 AOP 方法進行模塊化。Spring 支持使用 Spring AOP 框架的聲明式事務管理。

Spring 事務抽象
Spring 事務抽象的關鍵是由 org.springframework.transaction.PlatformTransactionManager 接口定義,如下所示:
在這裏插入圖片描述
在這裏插入圖片描述
TransactionDefinition 是在 Spring 中事務支持的核心接口,它的定義如下:
在這裏插入圖片描述
TransactionDefinition 是在 Spring 中事務支持的核心接口,它的定義如下:
在這裏插入圖片描述
下面是隔離級別的可能值:
在這裏插入圖片描述
下面是傳播類型的可能值:
在這裏插入圖片描述
TransactionStatus 接口爲事務代碼提供了一個簡單的方法來控制事務的執行和查詢事務狀態。
在這裏插入圖片描述
在這裏插入圖片描述

Spring 編程式事務管理

編程式事務管理方法允許你在對你的源代碼編程的幫助下管理事務。這給了你極大地靈活性,但是它很難維護。

讓我們直接使用 PlatformTransactionManager 來實現編程式方法從而實現事務。要開始一個新事務,你需要有一個帶有適當的 transaction 屬性的 TransactionDefinition 的實例。這個例子中,我們使用默認的 transaction 屬性簡單的創建了 DefaultTransactionDefinition 的一個實例。

當 TransactionDefinition 創建後,你可以通過調用 getTransaction() 方法來開始你的事務,該方法會返回 TransactionStatus 的一個實例。 TransactionStatus 對象幫助追蹤當前的事務狀態,並且最終,如果一切運行順利,你可以使用 PlatformTransactionManager 的 commit() 方法來提交這個事務,否則的話,你可以使用 rollback() 方法來回滾整個操作。

StudentMarks.java 文件的內容:
在這裏插入圖片描述
數據訪問對象接口文件 StudentDAO.java 的內容:
在這裏插入圖片描述
DAO 接口 StudentDAO 實現類文件 StudentJDBCTemplate.java:
在這裏插入圖片描述
在這裏插入圖片描述
MainApp.java
在這裏插入圖片描述
配置文件 Beans.xml 的內容
在這裏插入圖片描述

Spring 聲明式事務管理

聲明式事務管理方法允許你在配置的幫助下而不是源代碼硬編程來管理事務。這意味着你可以將事務管理從事務代碼中隔離出來。你可以只使用註釋或基於配置的 XML 來管理事務。 bean 配置會指定事務型方法。下面是與聲明式事務相關的步驟:

  • 我們使用標籤,它創建一個事務處理的建議,同時,我們定義一個匹配所有方法的切入點,我們希望這些方法是事務型的並且會引用事務型的建議。
  • 如果在事務型配置中包含了一個方法的名稱,那麼創建的建議在調用方法之前就會在事務中開始進行。
  • 目標方法會在 try / catch 塊中執行。如果方法正常結束,AOP 建議會成功的提交事務,否則它執行回滾操作。

例子與前面代碼差不多,更改的是以下地方
DAO 接口 StudentDAO 實現類文件 StudentJDBCTemplate.java
在這裏插入圖片描述
配置文件 Beans.xml 的內容增加以下內容
在這裏插入圖片描述

十一、Spring Web MVC 框架

Spring web MVC 框架提供了模型-視圖-控制的體系結構和可以用來開發靈活、鬆散耦合的 web 應用程序的組件。MVC 模式導致了應用程序的不同方面(輸入邏輯、業務邏輯和 UI 邏輯)的分離,同時提供了在這些元素之間的鬆散耦合。

  • 模型封裝了應用程序數據,並且通常它們由 POJO 組成。
  • 視圖主要用於呈現模型數據,並且通常它生成客戶端的瀏覽器可以解釋的 HTML 輸出。
  • 控制器主要用於處理用戶請求,並且構建合適的模型並將其傳遞到視圖呈現

DispatcherServlet

Spring Web 模型-視圖-控制(MVC)框架是圍繞 DispatcherServlet 設計的,DispatcherServlet 用來處理所有的 HTTP 請求和響應。Spring Web MVC DispatcherServlet 的請求處理的工作流程如下圖所示:
在這裏插入圖片描述
下面是對應於 DispatcherServlet 傳入 HTTP 請求的事件序列:
收到一個 HTTP 請求後,DispatcherServlet 根據 HandlerMapping 來選擇並且調用適當的控制器。

  • 控制器接受請求,並基於使用的 GET 或 POST 方法來調用適當的 service 方法。Service 方法將設置基於定義的業務邏輯的模型數據,並返回視圖名稱到 DispatcherServlet 中。
  • DispatcherServlet 會從 ViewResolver 獲取幫助,爲請求檢取定義視圖。
  • 一旦確定視圖,DispatcherServlet 將把模型數據傳遞給視圖,最後呈現在瀏覽器中。
    上面所提到的所有組件,即 HandlerMapping、Controller 和 ViewResolver 是 WebApplicationContext 的一部分,而 WebApplicationContext 是帶有一些對 web 應用程序必要的額外特性的 ApplicationContext 的擴展。

需求的配置
需要映射你想讓 DispatcherServlet 處理的請求,通過使用在 web.xml 文件中的一個 URL 映射。

web.xml 文件將被保留在你的應用程序的 WebContent/WEB-INF 目錄下。好的,在初始化 HelloWeb DispatcherServlet 時,該框架將嘗試加載位於該應用程序的 WebContent/WEB-INF 目錄中文件名爲 [servlet-name]-servlet.xml 的應用程序內容。在這種情況下,我們的文件將是 HelloWeb-servlet.xml。

接下來, 標籤表明哪些 URLs 將被 DispatcherServlet 處理。這裏所有以 .jsp 結束的 HTTP 請求將由 HelloWeb DispatcherServle t處理。

如果你不想使用默認文件名 [servlet-name]-servlet.xml 和默認位置 WebContent/WEB-INF,你可以通過在 web.xml 文件中添加 servlet 監聽器 ContextLoaderListener 自定義該文件的名稱和位置,如下所示:
在這裏插入圖片描述
檢查 HelloWeb-servlet.xml 文件的請求配置,該文件位於 web 應用程序的 WebContent/WEB-INF 目錄下:
在這裏插入圖片描述
以下是關於 HelloWeb-servlet.xml 文件的一些要點:

  • [servlet-name]-servlet.xml 文件將用於創建 bean 定義,重新定義在全局範圍內具有相同名稱的任何已定義的 bean。

  • 標籤將用於激活 Spring MVC 註釋掃描功能,該功能允許使用註釋,如 @Controller 和 @RequestMapping 等等。

  • InternalResourceViewResolver 將使用定義的規則來解決視圖名稱。按照上述定義的規則,一個名稱爲 hello 的邏輯視圖將發送給位於 /WEB-INF/jsp/hello.jsp 中實現的視圖。

定義控制器
DispatcherServlet 發送請求到控制器中執行特定的功能。@Controller 註釋表明一個特定類是一個控制器的作用。@RequestMapping 註釋用於映射 URL 到整個類或一個特定的處理方法。
在這裏插入圖片描述
@Controller 註釋定義該類作爲一個 Spring MVC 控制器。在這裏,第一次使用的 @RequestMapping 表明在該控制器中處理的所有方法都是相對於 /hello 路徑的。下一個註釋 @RequestMapping(method = RequestMethod.GET) 用於聲明 printHello() 方法作爲控制器的默認 service 方法來處理 HTTP GET 請求。你可以在相同的 URL 中定義其他方法來處理任何 POST 請求。

可以用另一種形式來編寫上面的控制器,你可以在 @RequestMapping 中添加額外的屬性,如下所示:
在這裏插入圖片描述
創建 JSP 視圖
對於不同的表示技術,Spring MVC 支持許多類型的視圖。這些包括 JSP、HTML、PDF、Excel 工作表、XML、Velocity 模板、XSLT、JSON、Atom 和 RSS 提要、JasperReports 等等。但我們最常使用利用 JSTL 編寫的 JSP 模板。所以讓我們在 /WEB-INF/hello/hello.jsp 中編寫一個簡單的 hello 視圖:
在這裏插入圖片描述

Spring Web MVC例子

HelloController.java 文件的內容:
在這裏插入圖片描述
web.xml 的內容
在這裏插入圖片描述
HelloWeb-servlet.xml 的內容
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章