1.Spring 基于注解的配置
基于注解的配置
從 Spring 2.5 開始就可以使用注解來配置依賴注入。而不是采用 XML 來描述一個 bean 連線,你可以使用相關類,方法或字段聲明的注解,將 bean 配置移動到組件類本身。
在 XML 注入之前進行注解注入,因此后者的配置將通過兩種方式的屬性連線被前者重寫。
注解連線在默認情況下在 Spring 容器中不打開。因此,在可以使用基于注解的連線之前,我們將需要在我們的 Spring 配置文件中啟用它。所以如果你想在 Spring 應用程序中使用的任何注解,可以考慮到下面的配置文件。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
? ? xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
? ? xmlns:context="http://www.springframework.org/schema/context"
? ? xsi:schemaLocation="http://www.springframework.org/schema/beans
? ? http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
? ? http://www.springframework.org/schema/context
? ? http://www.springframework.org/schema/context/spring-context-3.0.xsd">
? <context:annotation-config/>
? <!-- bean definitions go here -->
</beans>
一旦 被配置后,你就可以開始注解你的代碼,表明 Spring 應該自動連接值到屬性,方法和構造函數。讓我們來看看幾個重要的注解,并且了解它們是如何工作的:
序號注解 & 描述
@Required 注解應用于 bean 屬性的 setter 方法。
@Autowired 注解可以應用到 bean 屬性的 setter 方法,非 setter 方法,構造函數和屬性。
通過指定確切的將被連線的 bean,@Autowired 和 @Qualifier 注解可以用來刪除混亂。
Spring 支持 JSR-250 的基礎的注解,其中包括了 @Resource,@PostConstruct 和 @PreDestroy 注解。
2.Spring @Required 注釋
Spring @Required 注釋
@Required?注釋應用于 bean 屬性的 setter 方法,它表明受影響的 bean 屬性在配置時必須放在 XML 配置文件中,否則容器就會拋出一個 BeanInitializationException 異常。下面顯示的是一個使用 @Required 注釋的示例。
示例:
讓我們使 Eclipse IDE 處于工作狀態,請按照下列步驟創建一個 Spring 應用程序:
步驟描述
1創建一個名為?SpringExample?的項目,并且在所創建項目的?src?文件夾下創建一個名為?com.tutorialspoint?的包。
2使用?Add External JARs?選項添加所需的 Spring 庫文件,就如在?Spring Hello World Example?章節中解釋的那樣。
3在?com.tutorialspoint?包下創建 Java 類?Student?和?MainApp。
4在?src?文件夾下創建 Beans 配置文件?Beans.xml。
5最后一步是創建所有 Java 文件和 Bean 配置文件的內容,并且按如下解釋的那樣運行應用程序。
下面是?Student.java?文件的內容:
下面是?MainApp.java?文件的內容:
下面是配置文件?Beans.xml:?文件的內容:
? ? http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
? ? http://www.springframework.org/schema/context
? ? http://www.springframework.org/schema/context/spring-context-3.0.xsd">? ? ? ? ? ? ? ? ? ? ? ? ?
一旦你已經完成的創建了源文件和 bean 配置文件,讓我們運行一下應用程序。如果你的應用程序一切都正常的話,這將引起?BeanInitializationException?異常,并且會輸出一下錯誤信息和其他日志消息:
Property'age'is requiredforbean'student'
下一步,在你按照如下所示從 “age” 屬性中刪除了注釋,你可以嘗試運行上面的示例:
? ? http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
? ? http://www.springframework.org/schema/context
? ? http://www.springframework.org/schema/context/spring-context-3.0.xsd">? ? ? ? ? ? ? ? ? ?
現在上面的示例將產生如下結果:
3.Spring @Autowired 注釋
Spring @Autowired 注釋
@Autowired?注釋對在哪里和如何完成自動連接提供了更多的細微的控制。
@Autowired 注釋可以在 setter 方法中被用于自動連接 bean,就像 @Autowired 注釋,容器,一個屬性或者任意命名的可能帶有多個參數的方法。
Setter 方法中的 @Autowired
你可以在 XML 文件中的 setter 方法中使用?@Autowired?注釋來除去 元素。當 Spring遇到一個在 setter 方法中使用的 @Autowired 注釋,它會在方法中視圖執行?byType?自動連接。
示例
讓我們使 Eclipse IDE 處于工作狀態,然后按照如下步驟創建一個 Spring 應用程序:
步驟描述
1創建一個名為?SpringExample?的項目,并且在所創建項目的?src?文件夾下創建一個名為?com.tutorialspoint?的包。
2使用?Add External JARs?選項添加所需的 Spring 庫文件,就如在?Spring Hello World Example?章節中解釋的那樣。
3在?com.tutorialspoint?包下創建 Java 類?TextEditor,?SpellChecker?和?MainApp。
4在?src?文件夾下創建 Beans 配置文件?Beans.xml。
5最后一步是創建所有 Java 文件和 Bean 配置文件的內容,并且按如下解釋的那樣運行應用程序。
這里是?TextEditor.java?文件的內容:
下面是另一個依賴的類文件?SpellChecker.java?的內容:
下面是?MainApp.java?文件的內容:
下面是配置文件?Beans.xml:
? ? http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
? ? http://www.springframework.org/schema/context
? ? http://www.springframework.org/schema/context/spring-context-3.0.xsd">? ? ? ? ? ? ?
一旦你已經完成的創建了源文件和 bean 配置文件,讓我們運行一下應用程序。如果你的應用程序一切都正常的話,這將會輸出以下消息:
Inside SpellChecker constructor.
Inside checkSpelling.
屬性中的 @Autowired
你可以在屬性中使用?@Autowired?注釋來除去 setter 方法。當時使用 為自動連接屬性傳遞的時候,Spring 會將這些傳遞過來的值或者引用自動分配給那些屬性。所以利用在屬性中 @Autowired 的用法,你的?TextEditor.java?文件將變成如下所示:
下面是配置文件?Beans.xml:
? ? http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
? ? http://www.springframework.org/schema/context
? ? http://www.springframework.org/schema/context/spring-context-3.0.xsd">? ? ? ? ? ? ?
一旦你在源文件和 bean 配置文件中完成了上面兩處改變,讓我們運行一下應用程序。如果你的應用程序一切都正常的話,這將會輸出以下消息:
Inside TextEditor constructor.
Inside SpellChecker constructor.
Inside checkSpelling.
構造函數中的 @Autowired
你也可以在構造函數中使用 @Autowired。一個構造函數 @Autowired 說明當創建 bean 時,即使在 XML 文件中沒有使用 元素配置 bean ,構造函數也會被自動連接。讓我們檢查一下下面的示例。
這里是?TextEditor.java?文件的內容:
下面是配置文件?Beans.xml:
? ? http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
? ? http://www.springframework.org/schema/context
? ? http://www.springframework.org/schema/context/spring-context-3.0.xsd">? ? ? ? ? ? ?
一旦你在源文件和 bean 配置文件中完成了上面兩處改變,讓我們運行一下應用程序。如果你的應用程序一切都正常的話,這將會輸出以下消息:
Inside SpellChecker constructor.Inside TextEditor constructor.Inside checkSpelling.
@Autowired 的(required=false)選項
默認情況下,@Autowired 注釋意味著依賴是必須的,它類似于 @Required 注釋,然而,你可以使用 @Autowired 的?(required=false)?選項關閉默認行為。
即使你不為 age 屬性傳遞任何參數,下面的示例也會成功運行,但是對于 name 屬性則需要一個參數。你可以自己嘗試一下這個示例,因為除了只有?Student.java?文件被修改以外,它和 @Required 注釋示例是相似的。
4.Spring @Qualifier 注釋
Spring @Qualifier 注釋
可能會有這樣一種情況,當你創建多個具有相同類型的 bean 時,并且想要用一個屬性只為它們其中的一個進行裝配,在這種情況下,你可以使用?@Qualifier?注釋和?@Autowired?注釋通過指定哪一個真正的 bean 將會被裝配來消除混亂。下面顯示的是使用 @Qualifier 注釋的一個示例。
示例
讓我們使 Eclipse IDE 處于工作狀態,請按照下列步驟創建一個 Spring 應用程序:
步驟描述
1創建一個名為?SpringExample?的項目,并且在所創建項目的?src?文件夾下創建一個名為?com.tutorialspoint?的包。
2使用?Add External JARs?選項添加所需的 Spring 庫文件,就如在?Spring Hello World Example?章節中解釋的那樣。
3在?com.tutorialspoint?包下創建 Java 類?Student,Profile?和?MainApp。
4在?src?文件夾下創建 Beans 配置文件?Beans.xml。
5最后一步是創建所有 Java 文件和 Bean 配置文件的內容,并且按如下解釋的那樣運行應用程序。
這里是?Student.java?文件的內容:
這里是?Profile.java?文件的內容:
下面是?MainApp.java?文件的內容:
考慮下面配置文件?Beans.xml?的示例:
? ? http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
? ? http://www.springframework.org/schema/context
? ? http://www.springframework.org/schema/context/spring-context-3.0.xsd">? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
一旦你在源文件和 bean 配置文件中完成了上面兩處改變,讓我們運行一下應用程序。如果你的應用程序一切都正常的話,這將會輸出以下消息:
Inside Profile constructor.Age :11Name : Zara
5.Spring JSR-250 注釋
Spring JSR-250 注釋
Spring還使用基于 JSR-250 注釋,它包括 @PostConstruct, @PreDestroy 和 @Resource 注釋。因為你已經有了其他的選擇,盡管這些注釋并不是真正所需要的,但是關于它們仍然讓我給出一個簡短的介紹。
@PostConstruct 和 @PreDestroy 注釋:
為了定義一個 bean 的安裝和卸載,我們使用?init-method?和/或?destroy-method?參數簡單的聲明一下?。init-method 屬性指定了一個方法,該方法在 bean 的實例化階段會立即被調用。同樣地,destroy-method 指定了一個方法,該方法只在一個 bean 從容器中刪除之前被調用。
你可以使用?@PostConstruct?注釋作為初始化回調函數的一個替代,@PreDestroy?注釋作為銷毀回調函數的一個替代,其解釋如下示例所示。
示例
讓我們使 Eclipse IDE 處于工作狀態,請按照下列步驟創建一個 Spring 應用程序:
步驟描述
1創建一個名為?SpringExample?的項目,并且在所創建項目的?src?文件夾下創建一個名為?com.tutorialspoint?的包。
2使用?Add External JARs?選項添加所需的 Spring 庫文件,就如在?Spring Hello World Example?章節中解釋的那樣。
3在?com.tutorialspoint?包下創建 Java 類?HelloWorld?和?MainApp。
4在?src?文件夾下創建 Beans 配置文件?Beans.xml。
5最后一步是創建所有 Java 文件和 Bean 配置文件的內容,并且按如下解釋的那樣運行應用程序。
這里是?HelloWorld.java?文件的內容:
下面是?MainApp.java?文件的內容。這里你需要注冊一個關閉鉤?registerShutdownHook()?方法,該方法在 AbstractApplicationContext 類中被聲明。這將確保一個完美的關閉并調用相關的銷毀方法。
下面是配置文件?Beans.xml,該文件在初始化和銷毀方法中需要使用。
? ? http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
? ? http://www.springframework.org/schema/context
? ? http://www.springframework.org/schema/context/spring-context-3.0.xsd">? ? ? ? ? ?
一旦你在源文件和 bean 配置文件中完成了上面兩處改變,讓我們運行一下應用程序。如果你的應用程序一切都正常的話,這將會輸出以下消息:
Your Message : Hello World!
Bean will destroy now.
@Resource 注釋:
你可以在字段中或者 setter 方法中使用?@Resource?注釋,它和在 Java EE 5 中的運作是一樣的。@Resource 注釋使用一個 ‘name’ 屬性,該屬性以一個 bean 名稱的形式被注入。你可以說,它遵循?by-name?自動連接語義,如下面的示例所示:
如果沒有明確地指定一個 ‘name’,默認名稱源于字段名或者 setter 方法。在字段的情況下,它使用的是字段名;在一個 setter 方法情況下,它使用的是 bean 屬性名稱。
6.Spring 基于 Java 的配置
基于 Java 的配置
到目前為止,你已經看到如何使用 XML 配置文件來配置 Spring bean。如果你熟悉使用 XML 配置,那么我會說,不需要再學習如何進行基于 Java 的配置是,因為你要達到相同的結果,可以使用其他可用的配置。
基于 Java 的配置選項,可以使你在不用配置 XML 的情況下編寫大多數的 Spring,但是一些有幫助的基于 Java 的注解,解釋如下:
@Configuration 和 @Bean 注解
帶有?@Configuration?的注解類表示這個類可以使用 Spring IoC 容器作為 bean 定義的來源。@Bean?注解告訴 Spring,一個帶有 @Bean 的注解方法將返回一個對象,該對象應該被注冊為在 Spring 應用程序上下文中的 bean。最簡單可行的 @Configuration 類如下所示:
上面的代碼將等同于下面的 XML 配置:
在這里,帶有 @Bean 注解的方法名稱作為 bean 的 ID,它創建并返回實際的 bean。你的配置類可以聲明多個 @Bean。一旦定義了配置類,你就可以使用?AnnotationConfigApplicationContext?來加載并把他們提供給 Spring 容器,如下所示:
你可以加載各種配置類,如下所示:
例子
讓我們在恰當的位置使用 Eclipse IDE,然后按照下面的步驟來創建一個 Spring 應用程序:
步驟描述
1創建一個名稱為?SpringExample?的項目,并且在創建項目的?src?文件夾中創建一個包?com.tutorialspoint。
2使用?Add External JARs?選項,添加所需的 Spring 庫,解釋見?Spring Hello World Example?章節。
3因為你是使用基于 java 的注解,所以你還需要添加來自 Java 安裝目錄的?CGLIB.jar?和可以從?asm.ow2.org?中下載的 ASM.jar 庫。
4在?com.tutorialspoint?包中創建 Java 類?HelloWorldConfig、HelloWorld?和?MainApp。
5最后一步是創建的所有 Java 文件和 Bean 配置文件的內容,并運行應用程序,解釋如下所示。
這里是?HelloWorldConfig.java?文件的內容:
這里是?HelloWorld.java?文件的內容:
下面是?MainApp.java?文件的內容:
一旦你完成了創建所有的源文件并添加所需的額外的庫后,我們就可以運行該應用程序。你應該注意這里不需要配置文件。如果你的應用程序一切都正常,將輸出以下信息:
注入 Bean 的依賴性
當 @Beans 依賴對方時,表達這種依賴性非常簡單,只要有一個 bean 方法調用另一個,如下所示:
這里,foo Bean 通過構造函數注入來接收參考基準。現在,讓我們看到一個正在執行的例子:
例子:
讓我們在恰當的位置使用 Eclipse IDE,然后按照下面的步驟來創建一個 Spring 應用程序:
步驟描述
1創建一個名稱為?SpringExample?的項目,并且在創建項目的?src?文件夾中創建一個包?com.tutorialspoint。
2使用?Add External JARs?選項,添加所需的 Spring 庫,解釋見?Spring Hello World Example?章節。
3因為你是使用基于 java 的注解,所以你還需要添加來自 Java 安裝目錄的?CGLIB.jar?和可以從?asm.ow2.org?中下載的 ASM.jar 庫。
4在?com.tutorialspoint?包中創建 Java 類?TextEditorConfig、TextEditor、SpellChecker?和?MainApp。
5最后一步是創建的所有 Java 文件和 Bean 配置文件的內容,并運行應用程序,解釋如下所示。
這里是?TextEditorConfig.java?文件的內容:
這里是 TextEditor.java 文件的內容:
下面是另一個依賴的類文件?SpellChecker.java?的內容:
下面是?MainApp.java?文件的內容:
一旦你完成了創建所有的源文件并添加所需的額外的庫后,我們就可以運行該應用程序。你應該注意這里不需要配置文件。如果你的應用程序一切都正常,將輸出以下信息:
Inside SpellChecker constructor.
Inside TextEditor constructor.
Inside checkSpelling.
@Import 注解:
@import?注解允許從另一個配置類中加載 @Bean 定義。考慮 ConfigA 類,如下所示:
@ConfigurationpublicclassConfigA{@BeanpublicAa(){returnnewA();? ? }}
你可以在另一個 Bean 聲明中導入上述 Bean 聲明,如下所示:
@Configuration@Import(ConfigA.class)publicclassConfigB{@BeanpublicBa(){returnnewA();? ? }}
現在,當實例化上下文時,不需要同時指定 ConfigA.class 和 ConfigB.class,只有 ConfigB 類需要提供,如下所示:
生命周期回調
@Bean 注解支持指定任意的初始化和銷毀的回調方法,就像在 bean 元素中 Spring 的 XML 的初始化方法和銷毀方法的屬性:
指定 Bean 的范圍:
默認范圍是單實例,但是你可以重寫帶有 @Scope 注解的該方法,如下所示:
@ConfigurationpublicclassAppConfig{@Bean@Scope("prototype")publicFoofoo(){returnnewFoo();? }}
7.Spring 中的事件處理
Spring 中的事件處理
你已經看到了在所有章節中 Spring 的核心是?ApplicationContext,它負責管理 beans 的完整生命周期。當加載 beans 時,ApplicationContext 發布某些類型的事件。例如,當上下文啟動時,ContextStartedEvent 發布,當上下文停止時,ContextStoppedEvent 發布。
通過 ApplicationEvent 類和 ApplicationListener 接口來提供在 ApplicationContext 中處理事件。如果一個 bean 實現 ApplicationListener,那么每次 ApplicationEvent 被發布到 ApplicationContext 上,那個 bean 會被通知。
Spring 提供了以下的標準事件:
序號Spring 內置事件 & 描述
1ContextRefreshedEvent
ApplicationContext 被初始化或刷新時,該事件被發布。這也可以在 ConfigurableApplicationContext 接口中使用 refresh() 方法來發生。
2ContextStartedEvent
當使用 ConfigurableApplicationContext 接口中的 start() 方法啟動 ApplicationContext 時,該事件被發布。你可以調查你的數據庫,或者你可以在接受到這個事件后重啟任何停止的應用程序。
3ContextStoppedEvent
當使用 ConfigurableApplicationContext 接口中的 stop() 方法停止 ApplicationContext 時,發布這個事件。你可以在接受到這個事件后做必要的清理的工作。
4ContextClosedEvent
當使用 ConfigurableApplicationContext 接口中的 close() 方法關閉 ApplicationContext 時,該事件被發布。一個已關閉的上下文到達生命周期末端;它不能被刷新或重啟。
5RequestHandledEvent
這是一個 web-specific 事件,告訴所有 bean HTTP 請求已經被服務。
由于 Spring 的事件處理是單線程的,所以如果一個事件被發布,直至并且除非所有的接收者得到的該消息,該進程被阻塞并且流程將不會繼續。因此,如果事件處理被使用,在設計應用程序時應注意。
監聽上下文事件
為了監聽上下文事件,一個 bean 應該實現只有一個方法?onApplicationEvent()?的 ApplicationListener 接口。因此,我們寫一個例子來看看事件是如何傳播的,以及如何可以用代碼來執行基于某些事件所需的任務。
讓我們在恰當的位置使用 Eclipse IDE,然后按照下面的步驟來創建一個 Spring 應用程序:
步驟描述
1創建一個名稱為 SpringExample 的項目,并且在創建項目的?src?文件夾中創建一個包 com.tutorialspoint。
2使用 Add External JARs 選項,添加所需的 Spring 庫,解釋見 Spring Hello World Example 章節。
3在 com.tutorialspoint 包中創建 Java 類 HelloWorld、CStartEventHandler、CStopEventHandler 和 MainApp。
4在?src?文件夾中創建 Bean 的配置文件 Beans.xml。
5最后一步是創建的所有 Java 文件和 Bean 配置文件的內容,并運行應用程序,解釋如下所示。
這里是?HelloWorld.java?文件的內容:
下面是?CStartEventHandler.java?文件的內容:
? implements ApplicationListener<ContextStartedEvent>{public void onApplicationEvent(ContextStartedEvent event) {? ? ? System.out.println("ContextStartedEvent Received");? }}
下面是?CStopEventHandler.java?文件的內容:
? implements ApplicationListener<ContextStoppedEvent>{public void onApplicationEvent(ContextStoppedEvent event) {? ? ? System.out.println("ContextStoppedEvent Received");? }}
下面是?MainApp.java?文件的內容:
下面是配置文件?Beans.xml?文件:
? ? http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"><bean id="helloWorld" class="com.tutorialspoint.HelloWorld"><property name="message" value="Hello World!"/></bean><bean id="cStartEventHandler"
? ? ? ? class="com.tutorialspoint.CStartEventHandler"/><bean id="cStopEventHandler"
? ? ? ? class="com.tutorialspoint.CStopEventHandler"/></beans>
一旦你完成了創建源和 bean 的配置文件,我們就可以運行該應用程序。如果你的應用程序一切都正常,將輸出以下消息:
ContextStartedEventReceivedYour Message : Hello World!ContextStoppedEvent Received
8.Spring 中的自定義事件
Spring 中的自定義事件
編寫和發布自己的自定義事件有許多步驟。按照在這一章給出的說明來編寫,發布和處理自定義 Spring 事件。
步驟描述
1創建一個名稱為 SpringExample 的項目,并且在創建項目的?src?文件夾中創建一個包 com.tutorialspoint。
2使用 Add External JARs 選項,添加所需的 Spring 庫,解釋見 Spring Hello World Example 章節。
3通過擴展?ApplicationEvent,創建一個事件類 CustomEvent。這個類必須定義一個默認的構造函數,它應該從 ApplicationEvent 類中繼承的構造函數。
4一旦定義事件類,你可以從任何類中發布它,假定 EventClassPublisher 實現了 ApplicationEventPublisherAware。你還需要在 XML 配置文件中聲明這個類作為一個 bean,之所以容器可以識別 bean 作為事件發布者,是因為它實現了 ApplicationEventPublisherAware 接口。
5發布的事件可以在一個類中被處理,假定 EventClassHandler 實現了 ApplicationListener 接口,而且實現了自定義事件的 onApplicationEvent 方法。
6在?src?文件夾中創建 bean 的配置文件 Beans.xml 和 MainApp 類,它可以作為一個 Spring 應用程序來運行。
7最后一步是創建的所有 Java 文件和 Bean 配置文件的內容,并運行應用程序,解釋如下所示。
這個是?CustomEvent.java?文件的內容:
下面是?CustomEventPublisher.java?文件的內容:
下面是?CustomEventHandler.java?文件的內容:
下面是?MainApp.java?文件的內容:
下面是配置文件?Beans.xml:
<?xml version="1.0"encoding="UTF-8"?>
? ? http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
一旦你完成了創建源和 bean 的配置文件后,我們就可以運行該應用程序。如果你的應用程序一切都正常,將輸出以下信息:
My Custom Event