1. 程式人生 > >spring 複習筆記

spring 複習筆記

Spring 框架提供約 20 個模組,可以根據應用程式的要求來使用

spring

1. 核心容器:
核心容器由核心,Bean,上下文和表示式語言模組組成,它們的細節如下:

核心模組提供了框架的基本組成部分,包括 IoC 和依賴注入功能。

Bean 模組提供 BeanFactory,它是一個工廠模式的複雜實現。

上下文模組建立在由核心和 Bean 模組提供的堅實基礎上,它是訪問定義和配置的任何物件的媒介。ApplicationContext 介面是上下文模組的重點。

表示式語言模組在執行時提供了查詢和操作一個物件圖的強大的表示式語言。


2. 資料訪問/整合:
資料訪問/整合層包括 JDBC,ORM,OXM,JMS 和事務處理模組,它們的細節如下:

JDBC 模組提供了刪除冗餘的 JDBC 相關編碼的 JDBC 抽象層。

ORM 模組為流行的物件關係對映 API,包括 JPA,JDO,Hibernate 和 iBatis,提供了整合層。

OXM 模組提供了抽象層,它支援對 JAXB,Castor,XMLBeans,JiBX 和 XStream 的物件/XML
對映實現。 Java 訊息服務 JMS 模組包含生產和消費的資訊的功能。 事務模組為實現特殊介面的類及所有的 POJO 支援程式設計式和宣告式事務管理。 3. Web: Web 層由 Web,Web-MVC,Web-Socket 和 Web-Portlet 組成,它們的細節如下: Web 模組提供了基本的面向 web 的整合功能,例如多個檔案上傳的功能和使用 servlet 監聽器和麵向 web 應用程式的上下文來初始化 IoC 容器。 Web-MVC 模組包含 Spring 的模型-檢視-控制器(MVC),實現了 web 應用程式。 Web-Socket 模組為 WebSocket-based
提供了支援,而且在 web 應用程式中提供了客戶端和伺服器端之間通訊的兩種方式。 Web-Portlet 模組提供了在 portlet 環境中實現 MVC,並且反映了 Web-Servlet 模組的功能。 4. 其他: 還有其他一些重要的模組,像 AOP,Aspects,Instrumentation,Web 和測試模組,它們的細節如下: AOP 模組提供了面向方面的程式設計實現,允許你定義方法攔截器和切入點對程式碼進行乾淨地解耦,它實現了應該分離的功能。 Aspects 模組提供了與 AspectJ 的整合,這是一個功能強大且成熟的面向切面程式設計(AOP)框架。 Instrumentation 模組在一定的應用伺服器中提供了類 instrumentation 的支援和類載入器的實現。 Messaging 模組為 STOMP 提供了支援作為在應用程式中 WebSocket 子協議的使用。它也支援一個註解程式設計模型,它是為了選路和處理來自 WebSocket 客戶端的 STOMP 資訊。 測試模組支援對具有 JUnit 或 TestNG 框架的 Spring 元件的測試。

這篇筆記主要用來記錄 核心容器:

IoC 容器

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

Spring 提供了以下兩種不同型別的容器。

1 Spring BeanFactory 容器:
它是最簡單的容器,給 DI 提供了基本的支援,它用 org.springframework.beans.factory.BeanFactory 介面來定義。BeanFactory 或者相關的介面,如 BeanFactoryAware,InitializingBean,DisposableBean,在 Spring 中仍然存在具有大量的與 Spring 整合的第三方框架的反向相容性的目的。

2 Spring ApplicationContext 容器:
該容器添加了更多的企業特定的功能,例如從一個屬性檔案中解析文字資訊的能力,釋出應用程式事件給感興趣的事件監聽器的能力。該容器是由 org.springframework.context.ApplicationContext 介面定義。

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

最常被使用的 ApplicationContext 介面實現:

FileSystemXmlApplicationContext:該容器從 XML 檔案中載入已被定義的 bean。在這裡,你需要提供給構造器 XML 檔案的完整路徑

ClassPathXmlApplicationContext:該容器從 XML 檔案中載入已被定義的 bean。在這裡,你不需要提供 XML 檔案的完整路徑,只需正確配置 CLASSPATH 環境變數即可,因為,容器會從 CLASSPATH 中搜索 bean 配置檔案。

WebXmlApplicationContext:該容器會在一個 web 應用程式的範圍內載入在 XML 檔案中已被定義的 bean。

一個簡單的示例:

public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = new FileSystemXmlApplicationContext
            ("C:/Users/ZARA/workspace/HelloSpring/src/Beans.xml");
      HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
      obj.getMessage();
   }
}

在主程式當中,我們需要注意以下兩點:

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

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

Bean 定義

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

bean 定義包含稱為配置元資料的資訊,下述容器也需要知道配置元資料:

  • 如何建立一個 bean
  • bean 的生命週期的詳細資訊
  • bean 的依賴關係

上述所有的配置元資料轉換成一組構成每個 bean 定義的下列屬性。

屬性 描述
class 這個屬性是強制性的,並且指定用來建立 bean 的 bean 類。
name 這個屬性指定唯一的 bean 識別符號。在基於 XML 的配置元資料中,你可以使用 ID 和/或 name 屬性來指定 bean 識別符號。
scope 這個屬性指定由特定的 bean 定義建立的物件的作用域,它將會在 bean 作用域的章節中進行討論。
constructor-arg 它是用來注入依賴關係的,並會在接下來的章節中進行討論。
properties 它是用來注入依賴關係的,並會在接下來的章節中進行討論。
autowiring mode 它是用來注入依賴關係的,並會在接下來的章節中進行討論。
lazy-initialization mode 延遲初始化的 bean 告訴 IoC 容器在它第一次被請求時,而不是在啟動時去建立一個 bean 例項。
initialization 方法 在 bean 的所有必需的屬性被容器設定之後,呼叫回撥方法。它將會在 bean 的生命週期章節中進行討論。
destruction 方法 當包含該 bean 的容器被銷燬時,使用回撥方法。它將會在 bean 的生命週期章節中進行討論。

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

  • 基於 XML 的配置檔案。
  • 基於註解的配置
  • 基於 Java 的配置

你已經看到了如何把基於 XML 的配置元資料提供給容器,但是讓我們看看另一個基於 XML 配置檔案的例子,這個配置檔案中有不同的 bean 定義,包括延遲初始化,初始化方法和銷燬方法的:

Bean 的作用域

Spring 框架支援以下五個作用域,如果你使用 web-aware ApplicationContext 時,其中最下面三個只在 web-aware Spring ApplicationContext 的上下文中有效。

作用域 描述
singleton 該作用域將 bean 的定義的限制在每一個 Spring IoC 容器中的一個單一例項(預設)。
prototype 該作用域將單一 bean 的定義限制在任意數量的物件例項。
request 該作用域將 bean 的定義限制為 HTTP 請求。
session 該作用域將 bean 的定義限制為 HTTP 會話。
global-session 該作用域將 bean 的定義限制為全域性 HTTP 會話。

singleton 作用域
如果作用域設定為 singleton,那麼 Spring IoC 容器剛好建立一個由該 bean 定義的物件的例項。該單一例項將儲存在這種單例 bean 的快取記憶體中,以及針對該 bean 的所有後續的請求和引用都返回快取物件。

預設作用域是始終是 singleton,但是當僅僅需要 bean 的一個例項時,你可以在 bean 的配置檔案中設定作用域的屬性為 singleton

prototype 作用域
如果作用域設定為 prototype,那麼每次特定的 bean 發出請求時 Spring IoC 容器就建立物件的新的 Bean 例項。一般說來,滿狀態的 bean 使用 prototype 作用域和沒有狀態的 bean 使用 singleton 作用域。

Bean 的生命週期

初始化回撥

  • 實現InitializingBean 介面
  • 在基於 XML 的配置元資料的情況下,你可以使用 init-method 屬性來指定帶有 void 無引數方法的名稱

銷燬回撥

  • 實現DisposableBean 介面
  • 在基於 XML 的配置元資料的情況下,你可以使用 destroy-method 屬性來指定帶有 void 無引數方法的名稱

如果在非 web 應用程式環境中使用 Spring 的 IoC 容器;例如在豐富的客戶端桌面環境中;那麼在 JVM 中你要註冊關閉 hook。這樣做可以確保正常關閉,為了讓所有的資源都被釋放,可以在單個 beans 上呼叫 destroy 方法。

context.registerShutdownHook();

建議你不要使用 InitializingBean 或者 DisposableBean 的回撥方法,因為 XML 配置在命名方法上提供了極大的靈活性。

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

Spring——Bean 後置處理器

BeanPostProcessor 介面定義回撥方法,你可以實現該方法來提供自己的例項化邏輯,依賴解析邏輯等。你也可以在 Spring 容器通過插入一個或多個 BeanPostProcessor 的實現來完成例項化,配置和初始化一個bean之後實現一些自定義邏輯回撥方法。

你可以配置多個 BeanPostProcesso r介面,通過設定 BeanPostProcessor 實現的 Ordered 介面提供的 order 屬性來控制這些 BeanPostProcessor 介面的執行順序

BeanPostProcessor 可以對 bean(或物件)例項進行操作,這意味著 Spring IoC 容器例項化一個 bean 例項,然後 BeanPostProcessor 介面進行它們的工作。

ApplicationContext 會自動檢測由 BeanPostProcessor 介面的實現定義的 bean,註冊這些 bean 為後置處理器,然後通過在容器中建立 bean,在適當的時候呼叫它。

輸出結果:

BeforeInitialization : life2
LifeCycle2->InitializingBean
AfterInitialization : life2
Your Message : life
LifeCycle2->DisposableBean

Bean 定義繼承

bean 定義可以包含很多的配置資訊,包括建構函式的引數,屬性值,容器的具體資訊例如初始化方法,靜態工廠方法名,等等。

子 bean 的定義繼承父定義的配置資料。子定義可以根據需要重寫一些值,或者新增其他值。

Spring Bean 定義的繼承與 Java 類的繼承無關,但是繼承的概念是一樣的。你可以定義一個父 bean 的定義作為模板和其他子 bean 就可以從父 bean 中繼承所需的配置。

當你使用基於 XML 的配置元資料時,通過使用父屬性,指定父 bean 作為該屬性的值來表明子 bean 的定義。

Bean 定義模板
你可以建立一個 Bean 定義模板,不需要花太多功夫它就可以被其他子 bean 定義使用。在定義一個 Bean 定義模板時,你不應該指定類的屬性,而應該指定帶 true 值的抽象屬性

依賴注入

普通方式的注入

  • 基於建構函式的依賴注入
<constructor-arg ref="spellChecker"/>
  • 基於設值函式的依賴注入
<property name="spellChecker" ref="spellChecker"/>

注入內部 Beans

<bean id="outerBean" class="...">
      <property name="target">
         <bean id="innerBean" class="..."/>
      </property>
</bean>

注入集合

<list>  它有助於連線,如注入一列值,允許重複。
<set>   它有助於連線一組值,但不能重複。
<map>   它可以用來注入名稱-值對的集合,其中名稱和值可以是任何型別。
<props> 它可以用來注入名稱-值對的集合,其中名稱和值都是字串型別。

Beans 自動裝配

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

自動裝配模式
下列自動裝配模式,它們可用於指示 Spring 容器為來使用自動裝配進行依賴注入。你可以使用 元素的 autowire 屬性為一個 bean 定義指定自動裝配模式。

模式 描述
no 這是預設的設定,它意味著沒有自動裝配,你應該使用顯式的bean引用來連線。你不用為了連線做特殊的事。在依賴注入章節你已經看到這個了。
byName 由屬性名自動裝配。Spring 容器看到在 XML 配置檔案中 bean 的自動裝配的屬性設定為 byName。然後嘗試匹配,並且將它的屬性與在配置檔案中被定義為相同名稱的 beans 的屬性進行連線。
byType 由屬性資料型別自動裝配。Spring 容器看到在 XML 配置檔案中 bean 的自動裝配的屬性設定為 byType。然後如果它的型別匹配配置檔案中的一個確切的 bean 名稱,它將嘗試匹配和連線屬性的型別。如果存在不止一個這樣的 bean,則一個致命的異常將會被丟擲。
constructor 類似於 byType,但該型別適用於建構函式引數型別。如果在容器中沒有一個建構函式引數型別的 bean,則一個致命錯誤將會發生。
autodetect Spring首先嚐試通過 constructor 使用自動裝配來連線,如果它不執行,Spring 嘗試通過 byType 來自動裝配。

自動裝配的侷限性
當自動裝配始終在同一個專案中使用時,它的效果最好。如果通常不使用自動裝配,它可能會使開發人員混淆的使用它來連線只有一個或兩個 bean 定義。不過,自動裝配可以顯著減少需要指定的屬性或構造器引數,但你應該在使用它們之前考慮到自動裝配的侷限性和缺點。

限制 描述
重寫的可能性 你可以使用總是重寫自動裝配的 設定來指定依賴關係。
原始資料型別 你不能自動裝配所謂的簡單型別包括基本型別,字串和類。
混亂的本質 自動裝配不如顯式裝配精確,所以如果可能的話儘可能使用顯式裝配。

基於註解的配置

從 Spring 2.5 開始就可以使用註解來配置依賴注入。而不是採用 XML 來描述一個 bean 連線,你可以使用相關類,方法或欄位宣告的註解,將 bean 配置移動到元件類本身。

在 XML 注入之前進行註解注入,因此後者的配置將通過兩種方式的屬性連線被前者重寫。

註解連線在預設情況下在 Spring 容器中不開啟。因此,在可以使用基於註解的連線之前,我們將需要在我們的 Spring 配置檔案中啟用它。所以如果你想在 Spring 應用程式中使用的任何註解,可以考慮到下面的配置檔案。

<context:annotation-config/>

一旦 被配置後,你就可以開始註解你的程式碼,表明 Spring 應該自動連線值到屬性,方法和建構函式。讓我們來看看幾個重要的註解,並且瞭解它們是如何工作的:

@Required
@Required 註解應用於 bean 屬性的 setter 方法。

@Autowired
@Autowired 註解可以應用到 bean 屬性的 setter 方法,非 setter 方法,建構函式和屬性。

@Qualifier
通過指定確切的將被連線的 bean,@Autowired@Qualifier 註解可以用來刪除混亂

JSR-250 Annotations
Spring 支援 JSR-250 的基礎的註解,其中包括了 @Resource@PostConstruct@PreDestroy 註解。

@Required

@Required 註釋應用於 bean 屬性的 setter 方法,它表明受影響的 bean 屬性在配置時必須放在 XML 配置檔案中,否則容器就會丟擲一個 BeanInitializationException 異常。下面顯示的是一個使用 @Required 註釋的示例。

@Autowired

@Autowired 註釋對在哪裡和如何完成自動連線提供了更多的細微的控制。

@Autowired 註釋可以在 setter 方法中被用於自動連線 bean,就像 @Autowired 註釋,容器,一個屬性或者任意命名的可能帶有多個引數的方法。

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

@Qualifier

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

JSR-250 註釋

Spring還使用基於 JSR-250 註釋,它包括 @PostConstruct@PreDestroy@Resource 註釋。因為你已經有了其他的選擇,儘管這些註釋並不是真正所需要的,但是關於它們仍然讓我給出一個簡短的介紹。

@PostConstruct@PreDestroy 註釋:
為了定義一個 bean 的安裝和解除安裝,我們使用 init-method 和/或 destroy-method 引數簡單的宣告一下 。init-method 屬性指定了一個方法,該方法在 bean 的例項化階段會立即被呼叫。同樣地,destroy-method 指定了一個方法,該方法只在一個 bean 從容器中刪除之前被呼叫。

你可以使用 @PostConstruct 註釋作為初始化回撥函式的一個替代,@PreDestroy 註釋作為銷燬回撥函式的一個替代,其解釋如下示例所示。

@Resource 註釋:
你可以在欄位中或者 setter 方法中使用 @Resource 註釋,它和在 Java EE 5 中的運作是一樣的。@Resource 註釋使用一個 ‘name’ 屬性,該屬性以一個 bean 名稱的形式被注入。你可以說,它遵循 by-name 自動連線語義

基於 Java 的配置

@Configuration 和 @Bean 註解
帶有 @Configuration 的註解類表示這個類可以使用 Spring IoC 容器作為 bean 定義的來源。@Bean 註解告訴 Spring,一個帶有 @Bean 的註解方法將返回一個物件,該物件應該被註冊為在 Spring 應用程式上下文中的 bean。

@Import 註解:
@import 註解允許從另一個配置類中載入 @Bean 定義。

指定 Bean 的範圍:
預設範圍是單例項,但是你可以重寫帶有 @Scope 註解的該方法

一個簡單的示例:

@Configuration
public class Configer {

    @Bean
    public Bean1 getBean1(){
        return new Bean1();
    }

}


@Configuration
@Import(Configer.class)
public class ConfigChilder {

    @Bean
    public Bean2 getBean2(){
        return new Bean2();
    }

}

public class MainApp {


    public static void main(String[] args) {
        @SuppressWarnings("resource")
        ApplicationContext applicationContext =   new AnnotationConfigApplicationContext(ConfigChilder.class);
        Bean1 bean1 = applicationContext.getBean(Bean1.class);
        bean1.setMessage1("hello");
        bean1.getMessage1();
        Bean2 bean2 = applicationContext.getBean(Bean2.class);
        bean2.setMessage1("hello-bean2");
        bean2.getMessage1();
    }

}

Spring 中的事件處理

當載入 beans 時,ApplicationContext 釋出某些型別的事件。例如,當上下文啟動時,ContextStartedEvent 釋出,當上下文停止時,ContextStoppedEvent 釋出。

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

Spring 提供了以下的標準事件:

  • ContextRefreshedEvent
    ApplicationContext 被初始化或重新整理時,該事件被髮布。這也可以在 ConfigurableApplicationContext 介面中使用 refresh() 方法來發生。

  • ContextStartedEvent
    當使用 ConfigurableApplicationContext 介面中的 start() 方法啟動 ApplicationContext 時,該事件被髮布。你可以調查你的資料庫,或者你可以在接受到這個事件後重啟任何停止的應用程式。

  • ContextStoppedEvent
    當使用 ConfigurableApplicationContext 介面中的 stop() 方法停止 ApplicationContext 時,釋出這個事件。你可以在接受到這個事件後做必要的清理的工作。

  • ContextClosedEvent
    當使用 ConfigurableApplicationContext 介面中的 close() 方法關閉 ApplicationContext 時,該事件被髮布。一個已關閉的上下文到達生命週期末端;它不能被重新整理或重啟。

  • RequestHandledEvent
    這是一個 web-specific 事件,告訴所有 bean HTTP 請求已經被服務。

一個簡單的示例

public class CStartEventHandler 
   implements ApplicationListener<ContextStartedEvent>{
   public void onApplicationEvent(ContextStartedEvent event) {
      System.out.println("ContextStartedEvent Received");
   }
}


public class MainApp {
   public static void main(String[] args) {
      ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      // Let us raise a start event.
      context.start();
      HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
      obj.getMessage();
      // Let us raise a stop event.
      context.stop();
   }
}

列印結果:
ContextStartedEvent Received
Your Message : msg
ContextStoppedEvent Received

AOP

分為註解 和 xml配置,這次主要使用註解

在Spring中啟用AspectJ註解支援
* 要在Spring應用中使用AspectJ註解,必須在classpath下包含AspectJ類庫:aopalliance.jar、aspectj.weaver.jar和spring-aspects.jar
* 將aop Schema新增到根元素中。
* 要在Spring IOC容器中啟用AspectJ註解支援,只要早bean配置檔案中定義一個空的XML元素
* 當Spring IOC容器偵測到bean配置檔案中的元素時,會自動為與AspectJ切面匹配的bean建立代理

用AspectJ註解宣告切面
* 要在Spring中宣告AspectJ切面,只需要在IOC容器中將切面宣告為bean例項。當在Spring IOC容器中初始化AspectJ切面之後,Spring IOC容器就會為那些與AspectJ切面相匹配的bean建立代理
* 在AspectJ註解中,切面只是一個帶有@AspectJ註解的Java類
* 通知是標註有某種註解的簡單的Java方法

AspectJ支援5種類型的通知註解:
* @Before:前置通知,在方法執行之前返回
* @After:後置通知,在方法執行後執行
* @AfterRunning:返回通知,在方法返回結果之後執行
* @AfterThrowing:異常通知,在方法丟擲異常之後
* @Around:環繞通知,圍繞著方法執行

利用方法簽名編寫AspectJ切入點表示式

最典型的切入點表示式時根據方法的簽名來匹配各種方法:
* -execution * com.yl.spring.aop.ArithmeticCalculator.(..):匹配ArithmeticCalculator中宣告的所有方法,第一個代表任意修飾符及任意返回值,第二個*代表任意方法,..匹配任意數量的引數。若目標類與介面與切面在同一個包中,可以省略包名。
* -execution public * ArithmeticCalculator.*(..):匹配ArithmeticCalculator介面的所有公有方法
* -execution public double ArithmeticCalculator.*(..):匹配ArithmeticCalculator中返回double型別數值的方法
* -execution public double ArithmeticCalculator.*(double, ..):匹配第一個引數為double型別的方法,..匹配任意數量任意型別的引數
* -execution public double ArithmeticCalculator.*(double, double):匹配引數型別為double,double型別的方法

一個基於aspectj 註解的示例:

pom.xml配置文件:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>${spring.version}</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>${aspectjrt.version}</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>${aspectjrt.version}</version>
</dependency>
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2</version>
</dependency>

xml配置文件:

<!-- 開啟註解 -->
<context:annotation-config />
<!-- 自動掃描 -->
<context:component-scan base-package="cn.sunxyz.spring.aop" />
<!-- 啟動 AspectJ 支援 -->
<aop:aspectj-autoproxy />

基於註解的類:

@Component
@Aspect
public class MyAdvice {

    @Pointcut("execution(* cn.sunxyz.spring.aop.*.*(..))") // expression
    private void businessService() {
    }

    // 在一個方法執行之前,執行通知。
    @Before("businessService()")
    public void doBeforeTask() {
        System.out.println("doBeforeTask.");
    }

    // 在一個方法執行之後,不考慮其結果,執行通知。
    @After("businessService()")
    public void doAfterTask() {
        System.out.println("doAfterTask.");
    }

    // 在一個方法執行之後,只有在方法成功完成時,才能執行通知。
    @AfterReturning(pointcut = "businessService()", returning = "retVal")
    public void doAfterReturnningTask(JoinPoint joinPoint, Object retVal) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("doAfterReturnningTask " + methodName + " return with " + retVal);
    }

    // 在一個方法執行之後,只有在方法退出丟擲異常時,才能執行通知
    @AfterThrowing(pointcut = "businessService()", throwing = "ex")
    public void doAfterThrowingTask(JoinPoint joinPoint, Exception ex) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("doAfterThrowingTask " + methodName + " occurs exception: " + ex);
    }

    // 在建議方法呼叫之前和之後,執行通知。
    @Around("businessService()")
    public Object doAroundTask(ProceedingJoinPoint jpoint) {
        Object result = null;
        String methodName = jpoint.getSignature().getName();
        // 執行目標方法
        try {
            // 前置通知
            System.out.println("The method " + methodName + " begins with " + Arrays.asList(jpoint.getArgs()));
            result = jpoint.proceed();
            // 返回通知
            System.out.println("The method " + methodName + " ends with " + Arrays.asList(jpoint.getArgs()));
        } catch (Throwable e) {
            // 異常通知
            System.out.println("The method " + methodName + " occurs expection : " + e);
            throw new RuntimeException(e);
        }
        // 後置通知
        System.out.println("The method " + methodName + " ends");
        return result;

    }
}

事務

事務的概念可以描述為具有以下四個關鍵屬性說成是 ACID:
* 原子性:事務應該當作一個單獨單元的操作,這意味著整個序列操作要麼是成功,要麼是失敗的。
* 一致性:這表示資料庫的引用完整性的一致性,表中唯一的主鍵等。
* 隔離性:可能同時處理很多有相同的資料集的事務,每個事務應該與其他事務隔離,以防止資料損壞。
* 永續性:一個事務一旦完成全部操作後,這個事務的結果必須是永久性的,不能因系統故障而從資料庫中刪除。

隔離級別:
* TransactionDefinition.ISOLATION_DEFAULT 這是預設的隔離級別。
* TransactionDefinition.ISOLATION_READ_COMMITTED 表明能夠阻止誤讀;可以發生不可重複讀和虛讀。
* TransactionDefinition.ISOLATION_READ_UNCOMMITTED 表明可以發生誤讀、不可重複讀和虛讀。
* TransactionDefinition.ISOLATION_REPEATABLE_READ 表明能夠阻止誤讀和不可重複讀;可以發生虛讀。
* TransactionDefinition.ISOLATION_SERIALIZABLE 表明能夠阻止誤讀、不可重複讀和虛讀。

傳播型別:
* TransactionDefinition.PROPAGATION_MANDATORY 支援當前事務;如果不存在當前事務,則丟擲一個異常。
* TransactionDefinition.PROPAGATION_NESTED 如果存在當前事務,則在一個巢狀的事務中執行。
* TransactionDefinition.PROPAGATION_NEVER 不支援當前事務;如果存在當前事務,則丟擲一個異常。
* TransactionDefinition.PROPAGATION_NOT_SUPPORTED 不支援當前事務;而總是執行非事務性。
* TransactionDefinition.PROPAGATION_REQUIRED 支援當前事務;如果不存在事務,則建立一個新的事務。
* TransactionDefinition.PROPAGATION_REQUIRES_NEW 建立一個新事務,如果存在一個事務,則把當前事務掛起。
* TransactionDefinition.PROPAGATION_SUPPORTS 支援當前事務;如果不存在,則執行非事務性。
* TransactionDefinition.TIMEOUT_DEFAULT 使用預設超時的底層事務系統,或者如果不支援超時則沒有。

相關介紹: