使用Spring進(jìn)行面向切面編程(AOP)

前言

面向切面編程(AOP)提供另外一種角度來思考程序結(jié)構(gòu),通過這種方式彌補(bǔ)了面向?qū)ο缶幊蹋∣OP)的不足。 除了類(classes)以外,AOP提供了 切面。切面對關(guān)注點進(jìn)行模塊化,例如橫切多個類型和對象的事務(wù)管理。 (這些關(guān)注點術(shù)語通常稱作 橫切(crosscutting) 關(guān)注點。)

Spring的一個關(guān)鍵的組件就是 AOP框架。 盡管如此,Spring IoC容器并不依賴于AOP,這意味著你可以自由選擇是否使用AOP,AOP提供強(qiáng)大的中間件解決方案,這使得Spring IoC容器更加完善。

Spring 2.0 AOP

Spring 2.0 引入了一種更加簡單并且更強(qiáng)大的方式來自定義切面,用戶可以選擇使用基于模式(schema-based)的方式或者使用@AspectJ注解。 這兩種風(fēng)格都完全支持通知(Advice)類型和AspectJ的切入點語言,雖然實際上仍然使用Spring AOP進(jìn)行織入(Weaving)。

本章主要討論Spring 2.0對基于模式和基于@AspectJ的AOP支持。請查閱"AOP聲明風(fēng)格的選擇"一節(jié)獲取 為你的應(yīng)用選擇適當(dāng)?shù)穆暶黠L(fēng)格的建議。Spring 2.0完全保留了對Spring 1.2的向下兼容性,下一章 將討論 Spring 1.2 API所提供的底層的AOP支持。

Spring中所使用的AOP:提供聲明式企業(yè)服務(wù),特別是為了替代EJB聲明式服務(wù)。 最重要的服務(wù)是 聲明性事務(wù)管理(declarative transaction management) , 這個服務(wù)建立在Spring的抽象事務(wù)管理(transaction abstraction)之上。

允許用戶實現(xiàn)自定義的切面,用AOP來完善OOP的使用。

這樣你可以把Spring AOP看作是對Spring的一種增強(qiáng),它使得Spring可以不需要EJB就能提供聲明式事務(wù)管理; 或者也可以使用Spring AOP框架的全部功能來實現(xiàn)自定義的切面。

本章首先 介紹了AOP的概念,無論你打算采用哪種風(fēng)格的切面聲明,這個部分都值得你一讀。 本章剩下的部分將著重于Spring 2.0對AOP的支持; 下一章 提供了關(guān)于Spring 1.2風(fēng)格的AOP概述,也許你已經(jīng)在其他書本,文章以及已有的應(yīng)用程序中碰到過這種AOP風(fēng)格。 如果你只打算使用通用的聲明式服務(wù)或者預(yù)先打包的聲明式中間件服務(wù),例如緩沖池(pooling), 那么你不必直接使用Spring AOP,而本章的大部分內(nèi)容也可以直接跳過。

1. AOP概念

首先讓我們從定義一些重要的AOP概念開始。這些術(shù)語不是Spring特有的。 不幸的是,AOP術(shù)語并不是特別的直觀;如果Spring使用自己的術(shù)語,將會變得更加令人困惑。 切面(Aspect): 一個關(guān)注點的模塊化,這個關(guān)注點可能會橫切多個對象。事務(wù)管理是J2EE應(yīng)用中一個關(guān)于橫切關(guān)注點的很好的例子。 在Spring AOP中,切面可以使用通用類(基于模式的風(fēng)格) 或者在普通類中以 @Aspect 注解(@AspectJ風(fēng)格)來實現(xiàn)。

  • 連接點(Joinpoint): 在程序執(zhí)行過程中某個特定的點,比如某方法調(diào)用的時候或者處理異常的時候。 在Spring AOP中,一個連接點 總是 代表一個方法的執(zhí)行。 通過聲明一個org.aspectj.lang.JoinPoint類型的參數(shù)可以使通知(Advice)的主體部分獲得連接點信息。
  • 通知(Advice): 在切面的某個特定的連接點(Joinpoint)上執(zhí)行的動作。通知有各種類型,其中包括“around”、“before”和“after”等通知。 通知的類型將在后面部分進(jìn)行討論。許多AOP框架,包括Spring,都是以攔截器做通知模型, 并維護(hù)一個以連接點為中心的攔截器鏈。
  • 切入點(Pointcut): 匹配連接點(Joinpoint)的斷言。通知和一個切入點表達(dá)式關(guān)聯(lián),并在滿足這個切入點的連接點上運(yùn)行(例如,當(dāng)執(zhí)行某個特定名稱的方法時)。 切入點表達(dá)式如何和連接點匹配是AOP的核心:Spring缺省使用AspectJ切入點語法。
  • 引入(Introduction): (也被稱為內(nèi)部類型聲明(inter-type declaration))。聲明額外的方法或者某個類型的字段。 Spring允許引入新的接口(以及一個對應(yīng)的實現(xiàn))到任何被代理的對象。 例如,你可以使用一個引入來使bean實現(xiàn) IsModified 接口,以便簡化緩存機(jī)制。
  • 目標(biāo)對象(Target Object): 被一個或者多個切面(aspect)所通知(advise)的對象。也有人把它叫做 被通知(advised) 對象。 既然Spring AOP是通過運(yùn)行時代理實現(xiàn)的,這個對象永遠(yuǎn)是一個 被代理(proxied) 對象。
  • AOP代理(AOP Proxy): AOP框架創(chuàng)建的對象,用來實現(xiàn)切面契約(aspect contract)(包括通知方法執(zhí)行等功能)。 在Spring中,AOP代理可以是JDK動態(tài)代理或者CGLIB代理。 注意:Spring 2.0最新引入的基于模式(schema-based)風(fēng)格和@AspectJ注解風(fēng)格的切面聲明,對于使用這些風(fēng)格的用戶來說,代理的創(chuàng)建是透明的。
  • 織入(Weaving): 把切面(aspect)連接到其它的應(yīng)用程序類型或者對象上,并創(chuàng)建一個被通知(advised)的對象。 這些可以在編譯時(例如使用AspectJ編譯器),類加載時和運(yùn)行時完成。 Spring和其他純Java AOP框架一樣,在運(yùn)行時完成織入。 通知的類型:前置通知(Before advice): 在某連接點(join point)之前執(zhí)行的通知,但這個通知不能阻止連接點前的執(zhí)行(除非它拋出一個異常)。
  • 返回后通知(After returning advice): 在某連接點(join point)正常完成后執(zhí)行的通知:例如,一個方法沒有拋出任何異常,正常返回。
  • 拋出異常后通知(After throwing advice): 在方法拋出異常退出時執(zhí)行的通知。
  • 后通知(After (finally) advice): 當(dāng)某連接點退出的時候執(zhí)行的通知(不論是正常返回還是異常退出)。
  • 環(huán)繞通知(Around Advice): 包圍一個連接點(join point)的通知,如方法調(diào)用。這是最強(qiáng)大的一種通知類型。 環(huán)繞通知可以在方法調(diào)用前后完成自定義的行為。它也會選擇是否繼續(xù)執(zhí)行連接點或直接返回它們自己的返回值或拋出異常來結(jié)束執(zhí)行。

環(huán)繞通知是最常用的一種通知類型。大部分基于攔截的AOP框架,例如Nanning和JBoss4,都只提供環(huán)繞通知。

跟AspectJ一樣,Spring提供所有類型的通知,我們推薦你使用盡量簡單的通知類型來實現(xiàn)需要的功能。 例如,如果你只是需要用一個方法的返回值來更新緩存,雖然使用環(huán)繞通知也能完成同樣的事情, 但是你最好使用After returning通知而不是環(huán)繞通知。 用最合適的通知類型可以使得編程模型變得簡單,并且能夠避免很多潛在的錯誤。 比如,你不需要調(diào)用 JoinPoint(用于Around Advice)的 proceed() 方法,就不會有調(diào)用的問題。

在Spring 2.0中,所有的通知參數(shù)都是靜態(tài)類型,因此你可以使用合適的類型(例如一個方法執(zhí)行后的返回值類型)作為通知的參數(shù)而不是使用一個對象數(shù)組。

切入點(pointcut)和連接點(join point)匹配的概念是AOP的關(guān)鍵,這使得AOP不同于其它僅僅提供攔截功能的舊技術(shù)。 切入點使得定位通知(advice)可獨(dú)立于OO層次。 例如,一個提供聲明式事務(wù)管理的around通知可以被應(yīng)用到一組橫跨多個對象中的方法上(例如服務(wù)層的所有業(yè)務(wù)操作)。

2. Spring AOP的功能和目標(biāo)

Spring AOP用純Java實現(xiàn)。它不需要專門的編譯過程。Spring AOP不需要控制類裝載器層次,因此它適用于J2EE web容器或應(yīng)用服務(wù)器。

Spring目前僅支持使用方法調(diào)用作為連接點(join point)(在Spring bean上通知方法的執(zhí)行)。 雖然可以在不影響到Spring AOP核心API的情況下加入對成員變量攔截器支持,但Spring并沒有實現(xiàn)成員變量攔截器。 如果你需要把對成員變量的訪問和更新也作為通知的連接點,可以考慮其它語法的Java語言,例如AspectJ。

Spring實現(xiàn)AOP的方法跟其他的框架不同。Spring并不是要嘗試提供最完整的AOP實現(xiàn)(盡管Spring AOP有這個能力), 相反的,它其實側(cè)重于提供一種AOP實現(xiàn)和Spring IoC容器的整合,用于幫助解決在企業(yè)級開發(fā)中的常見問題。

因此,Spring AOP通常都和Spring IoC容器一起使用。 Aspect使用普通的bean定義語法(盡管Spring提供了強(qiáng)大的“自動代理(autoproxying)”功能): 與其他AOP實現(xiàn)相比這是一個顯著的區(qū)別。有些事使用Spring AOP是無法輕松或者高效的完成的,比如說通知一個細(xì)粒度的對象。 這種時候,使用AspectJ是最好的選擇。不過經(jīng)驗告訴我們: 于大多數(shù)在J2EE應(yīng)用中遇到的問題,只要適合AOP來解決的,Spring AOP都沒有問題,Spring AOP提供了一個非常好的解決方案。

Spring AOP從來沒有打算通過提供一種全面的AOP解決方案來取代AspectJ。 我們相信無論是基于代理(proxy-based )的框架比如說Spring亦或是full-blown的框架比如說是AspectJ都是很有價值的,他們之間的關(guān)系應(yīng)該是互補(bǔ)而不是競爭的關(guān)系。 Spring 2.0可以無縫的整合Spring AOP,IoC 和AspectJ,使得所有的AOP應(yīng)用完全融入基于Spring的應(yīng)用體系。 這樣的集成不會影響Spring AOP API或者AOP Alliance API;Spring AOP保留了向下兼容性。接下來的一章會詳細(xì)討論Spring AOP API。

3. Spring的AOP代理

Spring缺省使用J2SE 動態(tài)代理(dynamic proxies)來作為AOP的代理。這樣任何接口都可以被代理。

Spring也支持使用CGLIB代理. 對于需要代理類而不是代理接口的時候CGLIB代理是很有必要的。 如果一個業(yè)務(wù)對象并沒有實現(xiàn)一個接口,默認(rèn)就會使用CGLIB。 作為面向接口編程的最佳實踐,業(yè)務(wù)對象通常都會實現(xiàn)一個或多個接口。但也有可能會 強(qiáng)制使用CGLIB, 在這種情況(希望不常有)下,你可能需要通知一個沒有在接口中聲明的方法,或者需要傳入一個代理對象給方法作為具體類型在Spring 2.0之后,Spring可能會提供多種其他類型的AOP代理,包括了完整的生成類。這不會影響到編程模型。

4. @AspectJ支持

"@AspectJ"使用了Java 5的注解,可以將切面聲明為普通的Java類。 AspectJ 5發(fā)布的 AspectJ project 中引入了這種@AspectJ風(fēng)格。 Spring 2.0 使用了和AspectJ 5一樣的注解,使用了AspectJ 提供的一個庫來做切點(pointcut)解析和匹配。 但是,AOP在運(yùn)行時仍舊是純的Spring AOP,并不依賴于AspectJ 的編譯器或者織入器(weaver)。 使用AspectJ的編譯器或者織入器(weaver)的話就可以使用完整的AspectJ 語言,我們將在 Section 6.8, “在Spring應(yīng)用中使用AspectJ” 中討論這個問題。

5. 啟用@AspectJ支持

為了在Spring配置中使用@AspectJ aspects,你必須首先啟用Spring對基于@AspectJ aspects的配置支持,自動代理(autoproxying)基于通知是否來自這些切面。 自動代理是指Spring會判斷一個bean是否使用了一個或多個切面通知,并據(jù)此自動生成相應(yīng)的代理以攔截其方法調(diào)用,并且確認(rèn)通知是否如期進(jìn)行。

通過在你的Spring的配置中引入下列元素來啟用Spring對@AspectJ的支持:

我們假使你正在使用 Appendix A, XML Schema-based configuration 所描述的schema支持。

如果你正在使用DTD,你仍舊可以通過在你的application context中添加如下定義來啟用@AspectJ支持:

你需要在你的應(yīng)用程序的classpath中引入兩個AspectJ庫:aspectjweaver.jar 和 aspectjrt.jar。 這些庫可以在AspectJ的安裝包(1.5.1或者之后的版本)中的 lib 目錄里找到,或者也可以在Spring依賴庫的 lib/aspectj 目錄下找到。

6. 聲明一個切面

在啟用@AspectJ支持的情況下,在application context中定義的任意帶有一個@Aspect切面(擁有@Aspect注解)的bean都將被Spring自動識別并用于配置在Spring AOP。 以下例子展示了為了完成一個不是非常有用的切面所需要的最小定義:

下面是在application context中的一個常見的bean定義,這個bean指向一個使用了 @Aspect 注解的bean類:

下面是 NotVeryUsefulAspect 類定義,使用了 org.aspectj.lang.annotation.Aspect 注解。

package org.xyz;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class NotVeryUsefulAspect {
}

切面(用 @Aspect 注解的類)和其他類一樣有方法和字段定義。他們也可能包括切入點,通知和引入(inter-type)聲明。

7. 聲明一個切入點(pointcut)

回想一下,切入點決定了連接點關(guān)注的內(nèi)容,使得我們可以控制通知什么時候執(zhí)行。 Spring AOP 只支持 Spring bean 方法執(zhí)行連接點。所以你可以把切入點看做是匹配 Spring bean 上方法的執(zhí)行。 一個切入點聲明有兩個部分:一個包含名字和任意參數(shù)的簽名,還有一個切入點表達(dá)式,該表達(dá)式?jīng)Q定了我們關(guān)注那個方法的執(zhí)行。 在 @AspectJ 注解風(fēng)格的 AOP 中,一個切入點簽名通過一個普通的方法定義來提供,并且切入點表達(dá)式使用 @Pointcut 注解來表示(作為切入點簽名的方法必須返回 void 類型)。

用一個例子會幫助我們區(qū)分切入點簽名和切入點表達(dá)式之間的差別,下面的例子定義了一個切入點'anyOldTransfer', 這個切入點將匹配任何名為 "transfer" 的方法的執(zhí)行:

@Pointcut("execution(* transfer(..))")// the pointcut expression
private void anyOldTransfer() {
}
// the pointcut signature

切入點表達(dá)式,也就是 @Pointcut 注解的值,是正規(guī)的AspectJ 5切入點表達(dá)式。 如果你想要更多了解AspectJ的 切入點語言,請參見 AspectJ 編程指南(如果要了解基于Java 5的擴(kuò)展請參閱 AspectJ 5 開發(fā)手冊) 或者其他人寫的關(guān)于AspectJ的書,例如Colyer et. al.著的《Eclipse AspectJ》或者Ramnivas Laddad著的《AspectJ in Action》。

8. 切入點指定者的支持

Spring AOP 支持在切入點表達(dá)式中使用如下的AspectJ切入點指定者:

其他的切入點類型

完整的AspectJ切入點語言支持額外的切入點指定者,但是Spring不支持這個功能。 他們分別是call, initialization, preinitialization, staticinitialization, get, set, handler, adviceexecution, withincode, cflow, cflowbelow, if, @this 和 @withincode。 在Spring AOP中使用這些指定者將會導(dǎo)致拋出IllegalArgumentException異常。

Spring AOP支持的切入點指定者可能在將來的版本中得到擴(kuò)展,不但支持更多的AspectJ 切入點指定者(例如"if"),還會支持某些Spring特有的切入點指定者,比如"bean"(用于匹配bean的名字)。 execution - 匹配方法執(zhí)行的連接點,這是你將會用到的Spring的最主要的切入點指定者。

  • within - 限定匹配特定類型的連接點(在使用Spring AOP的時候,在匹配的類型中定義的方法的執(zhí)行)。
  • this - 限定匹配特定的連接點(使用Spring AOP的時候方法的執(zhí)行),其中bean reference(Spring AOP 代理)是指定類型的實例。
  • target - 限定匹配特定的連接點(使用Spring AOP的時候方法的執(zhí)行),其中目標(biāo)對象(被代理的appolication object)是指定類型的實例。
  • args - 限定匹配特定的連接點(使用Spring AOP的時候方法的執(zhí)行),其中參數(shù)是指定類型的實例。
  • @target - 限定匹配特定的連接點(使用Spring AOP的時候方法的執(zhí)行),其中執(zhí)行的對象的類已經(jīng)有指定類型的注解。
  • @args - 限定匹配特定的連接點(使用Spring AOP的時候方法的執(zhí)行),其中實際傳入?yún)?shù)的運(yùn)行時類型有指定類型的注解。
  • @within - 限定匹配特定的連接點,其中連接點所在類型已指定注解(在使用Spring AOP的時候,所執(zhí)行的方法所在類型已指定注解)。
  • @annotation - 限定匹配特定的連接點(使用Spring AOP的時候方法的執(zhí)行),其中連接點的主題有某種給定的注解。 因為Spring AOP限制了連接點必須是方法執(zhí)行級別的,pointcut designators的討論也給出了一個定義,這個定義和AspectJ的編程指南中的定義相比顯得更加狹窄。 除此之外,AspectJ它本身有基于類型的語義,在執(zhí)行的連接點'this'和'target'都是指同一個對象,也就是執(zhí)行方法的對象。 Spring AOP是一個基于代理的系統(tǒng),并且嚴(yán)格區(qū)分代理對象本身(對應(yīng)于'this')和背后的目標(biāo)對象(對應(yīng)于'target') 6.2.3.2. 合并切入點表達(dá)式

切入點表達(dá)式可以使用using '&', '||' 和 '!'來合并.還可以通過名字來指向切入點表達(dá)式。 以下的例子展示了三種切入點表達(dá)式: anyPublicOperation(在一個方法執(zhí)行連接點代表了任意public方法的執(zhí)行時匹配); inTrading(在一個代表了在交易模塊中的任意的方法執(zhí)行時匹配) 和 tradingOperation(在一個代表了在交易模塊中的任意的公共方法執(zhí)行時匹配)。

@Pointcut("execution(public * *(..))")
    private void anyPublicOperation() {
}
@Pointcut("within(com.xyz.someapp.trading..*")
    private void inTrading() {
}
@Pointcut("anyPublicOperation() && inTrading()")
    private void tradingOperation() {
}

就上所示的,從更小的命名組件來構(gòu)建更加復(fù)雜的切入點表達(dá)式是一種最佳實踐。 當(dāng)用名字來指定切入點時使用的是常見的Java成員可視性訪問規(guī)則。 (比如說,你可以在同一類型中訪問私有的切入點,在繼承關(guān)系中訪問受保護(hù)的切入點,可以在任意地方訪問公共切入點。 成員可視性訪問規(guī)則不影響到切入點的 匹配。

9. 共享常見的切入點(pointcut)定義

當(dāng)開發(fā)企業(yè)級應(yīng)用的時候,你通常會想要從幾個切面來參考模塊化的應(yīng)用和特定操作的集合。 我們推薦定義一個“SystemArchitecture”切面來捕捉常見的切入點表達(dá)式。一個典型的切面可能看起來像下面這樣:

package com.xyz.someapp;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class SystemArchitecture {
    /**
   * A join point is in the web layer if the method is defined
   * in a type in the com.xyz.someapp.web package or any sub-package
   * under that.
   */
    @Pointcut("within(com.xyz.someapp.web..*)")
      public void inWebLayer() {
    }
    /**
   * A join point is in the service layer if the method is defined
   * in a type in the com.xyz.someapp.service package or any sub-package
   * under that.
   */
    @Pointcut("within(com.xyz.someapp.service..*)")
      public void inServiceLayer() {
    }
    /**
   * A join point is in the data access layer if the method is defined
   * in a type in the com.xyz.someapp.dao package or any sub-package
   * under that.
   */
    @Pointcut("within(com.xyz.someapp.dao..*)")
      public void inDataAccessLayer() {
    }
    /**
   * A business service is the execution of any method defined on a service
   * interface. This definition assumes that interfaces are placed in the
   * "service" package, and that implementation types are in sub-packages.
   * 
   * If you group service interfaces by functional area (for example, 
   * in packages com.xyz.someapp.abc.service and com.xyz.def.service) then
   * the pointcut expression "execution(* com.xyz.someapp..service.*.*(..))"
   * could be used instead.
   */
    @Pointcut("execution(* com.xyz.someapp.service.*.*(..))")
      public void businessService() {
    }
    /**
   * A data access operation is the execution of any method defined on a 
   * dao interface. This definition assumes that interfaces are placed in the
   * "dao" package, and that implementation types are in sub-packages.
   */
    @Pointcut("execution(* com.xyz.someapp.dao.*.*(..))")
      public void dataAccessOperation() {
    }
}

示例中的切入點定義了一個你可以在任何需要切入點表達(dá)式的地方可引用的切面。

示例

Spring AOP 用戶可能會經(jīng)常使用 execution pointcut designator。執(zhí)行表達(dá)式的格式如下:

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)

除了返回類型模式(上面代碼片斷中的ret-type-pattern),名字模式和參數(shù)模式以外,所有的部分都是可選的。 返回類型模式?jīng)Q定了方法的返回類型必須依次匹配一個連接點。 你會使用的最頻繁的返回類型模式是 *,它代表了匹配任意的返回類型。 一個全稱限定的類型名將只會匹配返回給定類型的方法。名字模式匹配的是方法名。 你可以使用*通配符作為所有或者部分命名模式。 參數(shù)模式稍微有點復(fù)雜:() 匹配了一個不接受任何參數(shù)的方法, 而 (..) 匹配了一個接受任意數(shù)量參數(shù)的方法(零或者更多)。 模式 (*) 匹配了一個接受一個任何類型的參數(shù)的方法。 模式 (*,String) 匹配了一個接受兩個參數(shù)的方法,第一個可以是任意類型,第二個則必須是String類型。

  • 下面給出一些常見切入點表達(dá)式的例子。任意公共方法的執(zhí)行:execution(public * *(..))
  • 任何一個以“set”開始的方法的執(zhí)行:execution(* set*(..))
  • AccountService 接口的任意方法的執(zhí)行:execution(* com.xyz.service.AccountService.*(..))
  • 定義在service包里的任意方法的執(zhí)行:execution(* com.xyz.service.*.*(..))
  • 定義在service包或者子包里的任意方法的執(zhí)行:execution(* com.xyz.service..*.*(..))
  • 在service包里的任意連接點(在Spring AOP中只是方法執(zhí)行) :within(com.xyz.service.*)
  • 在service包或者子包里的任意連接點(在Spring AOP中只是方法執(zhí)行) :within(com.xyz.service..*)

實現(xiàn)了AccountService接口的代理對象的任意連接點(在Spring AOP中只是方法執(zhí)行) :this(com.xyz.service.AccountService)'this'binding form中用的更多

實現(xiàn)了AccountService接口的目標(biāo)對象的任意連接點(在Spring AOP中只是方法執(zhí)行) :target(com.xyz.service.AccountService)'target'binding form中用的更多

任何一個只接受一個參數(shù),且在運(yùn)行時傳入的參數(shù)實現(xiàn)了Serializable接口的連接點 (在Spring AOP中只是方法執(zhí)行)args(java.io.Serializable)'args'binding form中用的更多

請注意在例子中給出的切入點不同于 execution(* *(java.io.Serializable)): args只有在動態(tài)運(yùn)行時候傳入?yún)?shù)是可序列化的(Serializable)才匹配,而execution 在傳入?yún)?shù)的簽名聲明的類型實現(xiàn)了 Serializable 接口時候匹配。

有一個 @Transactional 注解的目標(biāo)對象中的任意連接點(在Spring AOP中只是方法執(zhí)行) @target(org.springframework.transaction.annotation.Transactional)'@target' 也可以在binding form中使用:請常見以下討論通知的章節(jié)中關(guān)于如何使得annotation對象可以在通知體內(nèi)訪問到的部分。

任何一個目標(biāo)對象聲明的類型有一個 @Transactional 注解的連接點(在Spring AOP中只是方法執(zhí)行)@within(org.springframework.transaction.annotation.Transactional)'@within'也可以在binding form中使用:- 請常見以下討論通知的章節(jié)中關(guān)于如何

# 鏈接 Java程序員福利"常用資料分享"

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,527評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,687評論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,640評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,957評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 72,682評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,011評論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,009評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,183評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,714評論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,435評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,665評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,148評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,838評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,251評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,588評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,379評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 48,627評論 2 380

推薦閱讀更多精彩內(nèi)容