SpringBoot AOP 記錄日志實例
散布于應(yīng)用中多處的功能(日志对碌、安全朽们、事務(wù)管理等)被稱為橫切關(guān)注點。把橫切關(guān)注點與業(yè)務(wù)邏輯分離是AOP要解決的問題叁丧。
在運行時,動態(tài)地將代碼切入到類的指定方法稚瘾、指定位置上.
這樣的編程思想就是面向切面的編程。
面向切面編程(AOP是Aspect Oriented Program的首字母縮寫) 铅协,我們知道,面向?qū)ο蟮奶攸c是繼承、多態(tài)和封裝苍柏。而封裝就要求將功能分散到不同的對象中去,這在軟件設(shè)計中往往稱為職責(zé)分配烛恤。
實際上也就是說碟贾,讓不同的類設(shè)計不同的方法币喧。這樣代碼就分散到一個個的類中去了。這樣做的好處是降低了代碼的復(fù)雜程度袱耽,使類可重用杀餐。
但是人們也發(fā)現(xiàn),在分散代碼的同時扛邑,也增加了代碼的重復(fù)性怜浅。什么意思呢?比如說恶座,我們在兩個類中,可能都需要在每個方法中做日志。按面向?qū)ο蟮脑O(shè)計方法设捐,我們就必須在兩個類的方法中都加入日志的內(nèi)容。也許他們是完全相同的凹嘲,但就是因為面向?qū)ο蟮脑O(shè)計讓類與類之間無法聯(lián)系,而不能將這些重復(fù)的代碼統(tǒng)一起來。
也許有人會說反肋,那好辦啊,我們可以將這段代碼寫在一個獨立的類獨立的方法里,然后再在這兩個類中調(diào)用。但是虽填,這樣一來兔港,這兩個類跟我們上面提到的獨立的類就有耦合了,它的改變會影響這兩個類藕漱。那么牍戚,有沒有什么辦法,能讓我們在需要的時候圆恤,隨意地加入代碼呢拆火?這種在運行時贩汉,動態(tài)地將代碼切入到類的指定方法括丁、指定位置上的編程思想就是面向切面的編程。
一般而言拦赠,我們管切入到指定類指定方法的代碼片段稱為切面,而切入到哪些類、哪些方法則叫切入點馁害。有了AOP,我們就可以把幾個類共有的代碼枫疆,抽取到一個切片中爵川,等到需要時再切入對象中去,從而改變其原有的行為息楔。這樣看來雁芙,AOP其實只是OOP的補充而已。
OOP從橫向上區(qū)分出一個個的類來钞螟,而AOP則從縱向上向?qū)ο笾屑尤胩囟ǖ拇a兔甘。有了AOP,OOP變得立體了鳞滨。如果加上時間維度洞焙,AOP使OOP由原來的二維變?yōu)槿S了,由平面變成立體了拯啦。從技術(shù)上來說澡匪,AOP基本上是通過代理機制實現(xiàn)的。
AOP在編程歷史上可以說是里程碑式的褒链,對OOP編程是一種十分有益的補充唁情。
最常見的一些橫切行為如下面這些:
日志記錄,跟蹤甫匹,優(yōu)化和監(jiān)控
事務(wù)的處理
持久化
性能的優(yōu)化
資源池甸鸟,如數(shù)據(jù)庫連接池的管理
系統(tǒng)統(tǒng)一的認證、權(quán)限管理等
應(yīng)用系統(tǒng)的異常捕捉及處理
針對具體行業(yè)應(yīng)用的橫切行為
在軟件業(yè)兵迅,AOP為Aspect Oriented Programming的縮寫抢韭,意為:面向切面編程,通過預(yù)編譯方式和運行期動態(tài)代理實現(xiàn)程序功能的統(tǒng)一維護的一種技術(shù)恍箭。AOP是OOP的延續(xù)刻恭,是軟件開發(fā)中的一個熱點,也是Spring框架中的一個重要內(nèi)容扯夭,是函數(shù)式編程的一種衍生范型鳍贾。利用AOP可以對業(yè)務(wù)邏輯的各個部分進行隔離鞍匾,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性骑科,同時提高了開發(fā)的效率候学。
在Spring中提供了面向切面編程的豐富支持,允許通過分離應(yīng)用的業(yè)務(wù)邏輯與系統(tǒng)級服務(wù)(例如審計(auditing)和事務(wù)(transaction)管理)進行內(nèi)聚性的開發(fā)纵散。
主要功能:
日志記錄,性能統(tǒng)計隐圾,安全控制伍掀,事務(wù)處理,異常處理等等暇藏。
OOP引入封裝蜜笤、繼承、多態(tài)等概念來建立一種對象層次結(jié)構(gòu)盐碱,用于模擬公共行為的一個集合把兔。不過OOP允許開發(fā)者定義縱向的關(guān)系,但并不適合定義橫向的關(guān)系瓮顽,例如日志功能县好。日志代碼往往橫向地散布在所有對象層次中,而與它對應(yīng)的對象的核心功能毫無關(guān)系對于其他類型的代碼暖混,如安全性缕贡、異常處理和透明的持續(xù)性也都是如此,這種散布在各處的無關(guān)的代碼被稱為橫切(cross cutting)拣播,在OOP設(shè)計中晾咪,它導(dǎo)致了大量代碼的重復(fù),而不利于各個模塊的重用贮配。
AOP技術(shù)恰恰相反谍倦,它利用一種稱為"橫切"的技術(shù),剖解開封裝的對象內(nèi)部泪勒,并將那些影響了多個類的公共行為封裝到一個可重用模塊昼蛀,并將其命名為"Aspect",即切面圆存。所謂"切面"曹洽,簡單說就是那些與業(yè)務(wù)無關(guān),卻為業(yè)務(wù)模塊所共同調(diào)用的邏輯或責(zé)任封裝起來辽剧,便于減少系統(tǒng)的重復(fù)代碼送淆,降低模塊之間的耦合度,并有利于未來的可操作性和可維護性怕轿。
使用"橫切"技術(shù)偷崩,AOP把軟件系統(tǒng)分為兩個部分:核心關(guān)注點和橫切關(guān)注點辟拷。業(yè)務(wù)處理的主要流程是核心關(guān)注點,與之關(guān)系不大的部分是橫切關(guān)注點阐斜。橫切關(guān)注點的一個特點是衫冻,他們經(jīng)常發(fā)生在核心關(guān)注點的多處,而各處基本相似谒出,比如權(quán)限認證隅俘、日志、事物笤喳。AOP的作用在于分離系統(tǒng)中的各種關(guān)注點为居,將核心關(guān)注點和橫切關(guān)注點分離開來。
AOP核心概念
1杀狡、橫切關(guān)注點
對哪些方法進行攔截蒙畴,攔截后怎么處理,這些關(guān)注點稱之為橫切關(guān)注點
2呜象、切面(aspect)
類是對物體特征的抽象膳凝,切面就是對橫切關(guān)注點的抽象
3、連接點(joinpoint)
被攔截到的點,因為Spring只支持方法類型的連接點,所以在Spring中連接點指的就是被攔截到的方法盟步,實際上連接點還可以是字段或者構(gòu)造器
4、切入點(pointcut)
對連接點進行攔截的定義
5祟绊、通知(advice)
所謂通知指的就是指攔截到連接點之后要執(zhí)行的代碼,通知分為前置哥捕、后置牧抽、異常、最終遥赚、環(huán)繞通知五類
6扬舒、目標(biāo)對象
代理的目標(biāo)對象
7、織入(weave)
將切面應(yīng)用到目標(biāo)對象并導(dǎo)致代理對象創(chuàng)建的過程
8凫佛、引入(introduction)
在不修改代碼的前提下讲坎,引入可以在運行期為類動態(tài)地添加一些方法或字段
Spring對AOP的支持
Spring中AOP代理由Spring的IOC容器負責(zé)生成、管理愧薛,其依賴關(guān)系也由IOC容器負責(zé)管理晨炕。因此,AOP代理可以直接使用容器中的其它bean實例作為目標(biāo)毫炉,這種關(guān)系可由IOC容器的依賴注入提供瓮栗。Spring創(chuàng)建代理的規(guī)則為:
1、默認使用Java動態(tài)代理來創(chuàng)建AOP代理,這樣就可以為任何接口實例創(chuàng)建代理了
2费奸、當(dāng)需要代理的類不是代理接口的時候弥激,Spring會切換為使用CGLIB代理,也可強制使用CGLIB
AOP編程其實是很簡單的事情愿阐,縱觀AOP編程微服,程序員只需要參與三個部分:
1、定義普通業(yè)務(wù)組件
2缨历、定義切入點以蕴,一個切入點可能橫切多個業(yè)務(wù)組件
3、定義增強處理辛孵,增強處理就是在AOP框架為普通業(yè)務(wù)組件織入的處理動作
所以進行AOP編程的關(guān)鍵就是定義切入點和定義增強處理丛肮,一旦定義了合適的切入點和增強處理,AOP框架將自動生成AOP代理觉吭,即:代理對象的方法=增強處理+被代理對象的方法。
重溫 AspectJ 中幾個必須要了解的概念:
Aspect: Aspect 聲明類似于 Java 中的類聲明仆邓,在 Aspect 中會包含著一些 Pointcut 以及相應(yīng)的 Advice鲜滩。
Joint point:表示在程序中明確定義的點,典型的包括方法調(diào)用节值,對類成員的訪問以及異常處理程序塊的執(zhí)行等等徙硅,它自身還可以嵌套其它 joint point。
Pointcut:表示一組 joint point搞疗,這些 joint point 或是通過邏輯關(guān)系組合起來嗓蘑,或是通過通配、正則表達式等方式集中起來匿乃,它定義了相應(yīng)的 Advice 將要發(fā)生的地方桩皿。
Advice:Advice 定義了在 pointcut 里面定義的程序點具體要做的操作,它通過 before幢炸、after 和 around 來區(qū)別是在每個 joint point 之前泄隔、之后還是代替執(zhí)行的代碼。
下面要討論的這些問題宛徊,也許正是接觸了 AOP 之后所困惑的佛嬉。
AOP 幫助我們解決了新的問題沒有?
AOP 并沒有幫助我們解決任何新的問題闸天,它只是提供了一種更好的辦法暖呕,能夠用更少的工作量來解決現(xiàn)有的一些問題,并且使得系統(tǒng)更加健壯苞氮,可維護性更好湾揽。同時,它讓我們在進行系統(tǒng)架構(gòu)和模塊設(shè)計的時候多了新的選擇和新的思路。
實現(xiàn)AOP的切面主要有以下幾個要素:
@Aspect: 將一個java類定義為切面類
@Pointcut:定義一個切入點(規(guī)則表達式)
根據(jù)需要在切入點不同位置的切入內(nèi)容
@Before:在切入點開始處切入內(nèi)容
@After:在切入點結(jié)尾處切入內(nèi)容
@AfterReturning:在切入點return之后切入內(nèi)容(返回值回調(diào)钝腺,可以用來對處理返回值做一些加工處理)
@Around:在切入點前后切入內(nèi)容抛姑,并自己控制何時執(zhí)行切入點自身的內(nèi)容
@AfterThrowing:用來處理當(dāng)切入內(nèi)容部分拋出異常之后的處理邏輯
Spring AOP 依賴樹:
工程完整目錄:
~/KotlinSpringBoot/demo2_aop_logging$ tree
.
├── build
│ ├── kotlin
│ │ ├── compileKotlin
│ │ └── compileTestKotlin
│ └── kotlin-build
│ └── version.txt
├── build.gradle
├── demo2_aop_logging.iml
├── demo2_aop_logging.ipr
├── demo2_aop_logging.iws
├── demo2_aop_logging_main.iml
├── demo2_aop_logging_test.iml
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── src
├── main
│ ├── java
│ ├── kotlin
│ │ └── com
│ │ └── easy
│ │ └── springboot
│ │ └── demo2_aop_logging
│ │ └── Demo2AopLoggingApplication.kt
│ └── resources
│ ├── application.properties
│ ├── static
│ └── templates
└── test
├── java
├── kotlin
│ └── com
│ └── easy
│ └── springboot
│ └── demo2_aop_logging
│ └── Demo2AopLoggingApplicationTests.kt
└── resources
26 directories, 14 files
寫一個測試的Http 接口 Controller
package com.easy.springboot.demo2_aop_logging.controller
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController
@RestController
class HelloAopController {
@GetMapping("hello")
fun hello(): World {
return World(name = "AOP", id = "1002")
}
data class World(var name: String, var id: String)
}
響應(yīng)
// 20180101203831
// http://127.0.0.1:8080/hello
{
"name": "AOP",
"id": "1002"
}
除了引入spring框架dist目錄下的org.springframework.aop jar之外,還需要自己下載第三方依賴包:
aspectjweaver.jar
在 build.gradle 中添加依賴 spring-boot-starter-aop
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop
compile group: 'org.springframework.boot', name: 'spring-boot-starter-aop', version: '2.0.0.M7'
引入以上jar包之后艳狐,就可以通過@Aspect等注解方式進行AOP編程了.
切面邏輯實現(xiàn):
LogAspect.kt
package com.easy.springboot.demo2_aop_logging.aop
import org.aspectj.lang.JoinPoint
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.*
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Component
import org.springframework.web.context.request.RequestContextHolder
import org.springframework.web.context.request.ServletRequestAttributes
import java.util.*
@Component
@Aspect
class LogAspect {
private val LOG = LoggerFactory.getLogger(LogAspect::class.java)
@Pointcut("execution(public * com.easy.springboot.demo2_aop_logging.controller.*.*(..))") //.*.*代表所有子目錄下的所有方法定硝,最后括號里(..)的兩個..代表所有參數(shù)
fun logPointCut() {
}
@Before("logPointCut()")
@Throws(Throwable::class)
fun doBefore(joinPoint: JoinPoint) {
// 接收到請求,記錄請求內(nèi)容
val attributes = RequestContextHolder.getRequestAttributes() as ServletRequestAttributes
val request = attributes.request
// 記錄下請求內(nèi)容
LOG.info("請求地址 : " + request.requestURL.toString())
LOG.info("HTTP METHOD : " + request.method)
LOG.info("IP : " + request.remoteAddr)
LOG.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "."
+ joinPoint.getSignature().getName())
LOG.info("參數(shù) : " + Arrays.toString(joinPoint.getArgs()))
}
@AfterReturning(returning = "ret", pointcut = "logPointCut()")// returning的值和doAfterReturning的參數(shù)名一致
@Throws(Throwable::class)
fun doAfterReturning(ret: Any) {
// 處理完請求毫目,返回內(nèi)容
LOG.info("返回值 : " + ret)
}
@Around("logPointCut()")
@Throws(Throwable::class)
fun doAround(pjp: ProceedingJoinPoint): Any {
val startTime = System.currentTimeMillis()
val ob = pjp.proceed()// ob 為方法的返回值
LOG.info("耗時 : " + (System.currentTimeMillis() - startTime))
return ob
}
}
其中 execution 用于匹配方法執(zhí)行的連接點:
within:用于匹配指定類型內(nèi)的方法執(zhí)行蔬啡;
this:用于匹配當(dāng)前AOP代理對象類型的執(zhí)行方法;注意是AOP代理對象的類型匹配镀虐,這樣就可能包括引入接口也類型匹配箱蟆;
target:用于匹配當(dāng)前目標(biāo)對象類型的執(zhí)行方法;注意是目標(biāo)對象的類型匹配刮便,這樣就不包括引入接口也類型匹配空猜;
args:用于匹配當(dāng)前執(zhí)行的方法傳入的參數(shù)為指定類型的執(zhí)行方法;
@within:用于匹配所以持有指定注解類型內(nèi)的方法恨旱;
@target:用于匹配當(dāng)前目標(biāo)對象類型的執(zhí)行方法辈毯,其中目標(biāo)對象持有指定的注解;
@args:用于匹配當(dāng)前執(zhí)行的方法傳入的參數(shù)持有指定注解的執(zhí)行搜贤;
@annotation:用于匹配當(dāng)前執(zhí)行方法持有指定注解的方法谆沃;
bean:Spring AOP擴展的,AspectJ沒有對于指示符仪芒,用于匹配特定名稱的Bean對象的執(zhí)行方法唁影;
reference pointcut:表示引用其他命名切入點,只有@ApectJ風(fēng)格支持掂名,Schema風(fēng)格不支持据沈。
AspectJ切入點支持的切入點指示符還有: call、get饺蔑、set卓舵、preinitialization、staticinitialization膀钠、initialization掏湾、handler、adviceexecution肿嘲、withincode融击、cflow、cflowbelow雳窟、if尊浪、@this匣屡、@withincode;但Spring AOP目前不支持這些指示符拇涤,使用這些指示符將拋出IllegalArgumentException異常捣作。
類型匹配語法:
AspectJ類型匹配的通配符:
*:匹配任何數(shù)量字符;
..:匹配任何數(shù)量字符的重復(fù)鹅士,如在類型模式中匹配任何數(shù)量子包券躁;而在方法參數(shù)模式中匹配任何數(shù)量參數(shù)。
+:匹配指定類型的子類型掉盅;僅能作為后綴放在類型模式后邊也拜。
再次請求
// 20180101212902
// http://127.0.0.1:8080/hello
{
"name": "AOP",
"id": "1002"
}
我們可以看到后臺的日志輸出:
完整的文本如下:
2018-01-01 21:29:01.138 INFO 36572 --- [nio-8080-exec-1] c.e.s.demo2_aop_logging.aop.LogAspect : 請求地址 : http://127.0.0.1:8080/hello
2018-01-01 21:29:01.138 INFO 36572 --- [nio-8080-exec-1] c.e.s.demo2_aop_logging.aop.LogAspect : HTTP METHOD : GET
2018-01-01 21:29:01.138 INFO 36572 --- [nio-8080-exec-1] c.e.s.demo2_aop_logging.aop.LogAspect : IP : 127.0.0.1
2018-01-01 21:29:01.141 INFO 36572 --- [nio-8080-exec-1] c.e.s.demo2_aop_logging.aop.LogAspect : CLASS_METHOD : com.easy.springboot.demo2_aop_logging.controller.HelloAopController.hello
2018-01-01 21:29:01.141 INFO 36572 --- [nio-8080-exec-1] c.e.s.demo2_aop_logging.aop.LogAspect : 參數(shù) : []
2018-01-01 21:29:01.147 INFO 36572 --- [nio-8080-exec-1] c.e.s.demo2_aop_logging.aop.LogAspect : 耗時 : 10
2018-01-01 21:29:01.147 INFO 36572 --- [nio-8080-exec-1] c.e.s.demo2_aop_logging.aop.LogAspect : 返回值 : World(name=AOP, id=1002)
關(guān)于AspectJ 中的pointcut 語法
這兩天忙著看AspectJ in Action 為了補一下AOP知識≈憾唬看了Spring 2.0的規(guī)范慢哈,其中AOP部分已經(jīng)基本融合了AspectJ,看來有必要看一看AspectJ了永票。
看了很多AOP的文章了卵贱,AOP這兩年發(fā)展的很慢,沒有什么新意侣集,現(xiàn)在到處都是SOA键俱,SCA了,不過研究了一下肚吏,覺得還是很有幫助的方妖。尤其是增加系統(tǒng)的契約性和模塊的獨立性來說狭魂,很有幫助罚攀。
當(dāng)然,學(xué)東西雌澄,基礎(chǔ)很重要斋泄。下面就說說AspectJ中的基本語法,有興趣的可以看看AspectJ in Action镐牺。
先來說說pointcut炫掐,從字面的意思說的是切面的意思。也就是橫切的時候睬涧,會有哪些執(zhí)行點會被識別募胃。只有先識別了,才能執(zhí)行相應(yīng)的Advice畦浓。
基本的定義如下:
public pointcut accountOperations:call(* Account.*(..))
1.通配符和pointcut 操作符
-
表示任何數(shù)量的字符痹束,除了(.)
.. 表示任何數(shù)量的字符包括任何數(shù)量的(.)- 描述指定類型的任何子類或者子接口
同java一樣,提供了一元和二元的條件表達操作符讶请。
一元操作符:!
二元操作符:||和&&
優(yōu)先權(quán)同java
2.簽名語法
- 描述指定類型的任何子類或者子接口
類型簽名樣式
主要的例子:
Account 類型Account
Account 使用Account名稱結(jié)束的類型祷嘶,如SavingsAccount和CheckingAccount
java..Date 類型Date在任何直接的java子包中,如java.util.Date和java.sql.Date
java..* 任何在java包或者所有子包中的類型,如java.awt和java.util或者java.awt.event 和java.util.logging
javax..*Model+ 所有javax包或者子包中以Model結(jié)尾的類型和其所有子類论巍,如TableModel,TreeModel烛谊。
!vector 所有除了Vector的類型
Vector|| Hashtable Vector或者Hashtable類型
java.util.RandomAccess+ 實現(xiàn)RandomAccess和List的所有子類
&& java.util.List+
方法和構(gòu)造器簽名模式
public void Collection.clear():
在Collection中同樣簽名的clear方法
public void Account.debit(float) throws InsufficientBalanceException:
Account中同樣簽名的debit方法
public void Account.set()
Account中以set開頭嘉汰,并且只有一個參數(shù)類型的方法
public void Account.*()
Account中所有的沒有參數(shù)的public void 方法
public * Account.*()
Account中所有沒有參數(shù)的public 方法
public * Account.*(..)
Account中所有的public 方法
- Account.*(..)
Account中的所有方法丹禀,包括private方法
!public * Account.*(..)
所有的非public 方法
Account+.*(..)
所有的方法,包括子類的方法java.io.Reader.read(..)
所有的read方法java.io.Reader.read(char[],..)
所有以read(char[])開始的方法郑现,包括read(char[])和read(char[],int,int)javax...addListener(EventListener+)
命名以add開始湃崩,以Listener結(jié)尾的方法,參數(shù)中為EventListener或子類.(..) throws RemoteException
拋出RemoteException的所有方法
構(gòu)造器接箫,同上面
public Account.new()
沒有參數(shù)的構(gòu)造器方法
屬性簽名模式
同方法一樣攒读,屬性也查不多
* Account.*
所有的Account屬性
!public static * banking..*.*
所有的非public static 屬性,在banking的包或者子包中
3.主要的pointcuts類型
分類pointcuts
遵循特定的語法用于捕獲每一個種類的可使用連接點辛友。
主要的種類:
方法執(zhí)行:execution(MethodSignature)
方法調(diào)用:call(MethodSignature)
構(gòu)造器執(zhí)行:execution(ConstructorSignature)
構(gòu)造器調(diào)用:call(ConstructorSignature)
類初始化:staticinitialization(TypeSignature)
屬性讀操作:get(FieldSignature)
屬性寫操作:set(FieldSignature)
例外處理執(zhí)行:handler(TypeSignature)
對象初始化:initialization(ConstructorSignature)
對象預(yù)先初始化:preinitialization(ConstructorSignature)
Advice執(zhí)行:adviceexecution()
基于控制流的pointcuts
主要包括兩種類型的控制流:
cflow(Pointcut)薄扁,捕獲所有的連接點在指定的方法執(zhí)行中,包括執(zhí)行方法本身废累。
cflowbelow(Pointcut)邓梅,捕獲所有的連接點在指定的方法執(zhí)行中,除了執(zhí)行方法本身邑滨。
如以下的例子:
cflow(call(* Account.debit(..))
所有的debit方法中的連接點日缨,包括debit方法本身
cflowbelow(call(* Account.debit(..))
所有debit方法中的連接點,除了debit方法本身
cflow(transactedOperations())
所有由transactedOperations捕獲的連接點
cflowbelow(execution(Account.new(..))
所有在Account 構(gòu)造器中執(zhí)行的連接點
基于詞匯結(jié)構(gòu)的連接點
源代碼片斷掖看。匣距,如within()和withincode()
within :捕獲在指定類或者方面中的程序體中的所有連接點,包括內(nèi)部類哎壳。
Withincode:用于捕獲在構(gòu)造器或者方法中的所有連接點毅待,包括在其中的本地類
執(zhí)行對象連接點
匹配this,和target對象,作為方法被調(diào)用的對象归榕。
this(Account)尸红,所有Account的實例的執(zhí)行點,匹配所有的連接點刹泄,如方法調(diào)用外里,屬性設(shè)置,當(dāng)前的執(zhí)行對象為Account特石,或者其子類盅蝗。
target(Account):匹配所有的連接點,目標(biāo)對象為Account或其子類县匠。
必須執(zhí)行相應(yīng)的類型风科,不能使用*,或者..通配符撒轮。當(dāng)前靜態(tài)方法,不能被匹配贼穆。
在within()和this()中的區(qū)別:
一個是程序體题山,而另一個為對象執(zhí)行。
參數(shù)pointcuts
用于捕獲參數(shù)類型的連接點故痊。
args(String,..,int)
args(RemoteException)
條件檢測pointcuts
if(System.currentTimeMillis()>triggerTime)
本章示例工程源代碼: