SpringBoot AOP 記錄日志實例

SpringBoot AOP 記錄日志實例

image.png
image.png
image.png
image.png

散布于應(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ā)纵散。

image.png
image.png

主要功能:

日志記錄,性能統(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)容部分拋出異常之后的處理邏輯

image.png
image.png
image.png
image.png
image.png
image.png

Spring AOP 依賴樹:

image.png

工程完整目錄:

~/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編程了.

image.png

切面邏輯實現(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"
}

我們可以看到后臺的日志輸出:

image.png

完整的文本如下:

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)

本章示例工程源代碼:

https://github.com/KotlinSpringBoot/demo2_aop_logging

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末顶瞳,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子愕秫,更是在濱河造成了極大的恐慌慨菱,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件戴甩,死亡現(xiàn)場離奇詭異符喝,居然都是意外死亡,警方通過查閱死者的電腦和手機甜孤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門协饲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人缴川,你說我怎么就攤上這事茉稠。” “怎么了把夸?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵而线,是天一觀的道長。 經(jīng)常有香客問我恋日,道長膀篮,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任谚鄙,我火速辦了婚禮各拷,結(jié)果婚禮上刁绒,老公的妹妹穿的比我還像新娘闷营。我一直安慰自己,他們只是感情好知市,可當(dāng)我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布傻盟。 她就那樣靜靜地躺著,像睡著了一般嫂丙。 火紅的嫁衣襯著肌膚如雪娘赴。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天跟啤,我揣著相機與錄音诽表,去河邊找鬼唉锌。 笑死,一個胖子當(dāng)著我的面吹牛竿奏,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播泛啸,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼绿语,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了候址?” 一聲冷哼從身側(cè)響起吕粹,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎岗仑,沒想到半個月后匹耕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡荠雕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年泌神,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片舞虱。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡欢际,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出矾兜,到底是詐尸還是另有隱情损趋,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布椅寺,位于F島的核電站浑槽,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏返帕。R本人自食惡果不足惜桐玻,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望荆萤。 院中可真熱鬧镊靴,春花似錦、人聲如沸链韭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽敞峭。三九已至踊谋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間旋讹,已是汗流浹背殖蚕。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工轿衔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人睦疫。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓呀枢,卻偏偏與公主長得像,于是被迫代替她去往敵國和親笼痛。 傳聞我的和親對象是個殘疾皇子裙秋,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,786評論 2 345

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