Spring AOP 切點(diǎn)指示器

Spring AOP借助AspectJ的切點(diǎn)表達(dá)式語言來定義Spring切面勾徽,下面是切點(diǎn)表達(dá)式中使用的指示器:

  • execution
    這個(gè)是主要的切點(diǎn)指示器用來匹配方法執(zhí)行的連接點(diǎn)嚣鄙,也就是哪些方法要應(yīng)用切面
  • within
    用來限定連接點(diǎn)必須在確定的類型或包中
  • this
    用來限定連接點(diǎn)屬于給定類型的一個(gè)實(shí)例(代理對(duì)象)
  • target
    用來限定連接點(diǎn)屬于給定類型的一個(gè)實(shí)例(被代理對(duì)象)
  • args
    用來限定連接點(diǎn),也就是方法執(zhí)行時(shí)它的參數(shù)屬于給定類型的一個(gè)實(shí)例
  • @target
    用來限定連接點(diǎn)屬于一個(gè)執(zhí)行對(duì)象(被代理對(duì)象)所屬的擁有給定注解的類
  • @args
    用來限定連接點(diǎn)浙芙,方法執(zhí)行時(shí)傳遞的參數(shù)的運(yùn)行時(shí)類型擁有給定注解
  • @within
    用來限定連接點(diǎn)屬于擁有給定注解的類型中
  • @annotation
    用來限定連接點(diǎn)的方法擁有給定注解

下面將通過一些測(cè)試案例來說明以上各個(gè)切點(diǎn)指示器的用法。另外execution不作額外說明户辫,因?yàn)楸容^常見断国。

package com.drw.start.boot.test;

public interface Fruit {

    void print();
}

定義一個(gè)水果接口

package com.drw.start.boot.test;

import org.springframework.stereotype.Component;

@Component
public class SweetFruit implements Fruit {

    @Override
    public void print() {
        System.out.println("好吃的甜水果");
    }

    public void print(int i) {
        System.out.println("好吃的甜水果" + i);
    }
}

定義一個(gè)甜水果類

package com.drw.start.boot.test;

public interface Origin {

    void printOrigin();
}

定義一個(gè)產(chǎn)地接口

package com.drw.start.boot.test;

public interface FruitWeight {

    public int getWeight();
}

定義一個(gè)水果重量接口

package com.drw.start.boot.test;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;

@JsonDeserialize
public class AppleWeight implements FruitWeight {

    public int weight;

    public AppleWeight(int weight) {
        this.weight = weight;
    }

    @Override
    public int getWeight() {
        return weight;
    }

}

定義一個(gè)蘋果重量類

package com.drw.start.boot.test;

import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;

@Component
@Validated
public class RedApple extends SweetFruit implements Origin {


    @Override
    public void print() {
        System.out.println("好吃的紅蘋果");
    }

    @Override
    public void printOrigin() {
        System.out.println("浙江產(chǎn)的紅蘋果");
    }

    public void printPrice() {
        System.out.println("紅蘋果10塊一斤");
    }

    public void printPrice(Integer price) {
        System.out.println("紅蘋果" + price + "塊一斤");
    }

    public void printPrice(Integer price, String mesg) {
        System.out.println("紅蘋果" + price + "塊一斤");
    }


    public void printWeight(FruitWeight weight) {
        System.out.println("這個(gè)蘋果" + weight.getWeight() + "克");
    }

}

定義一個(gè)紅蘋果類

package com.drw.start.boot.test;

import org.springframework.stereotype.Component;

import com.fasterxml.jackson.databind.annotation.JsonSerialize;

@Component
public class FruitFarmer {

    @JsonSerialize
    public void print() {
        System.out.println("種水果的農(nóng)民");
    }

    @JsonSerialize
    public void worker() {
        System.out.println("果農(nóng)在勞動(dòng)");
    }
}

定義一個(gè)果農(nóng)類

package com.drw.start.boot.test;

import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class AopDesignatorTest {

    @Autowired
    @Qualifier("sweetFruit")
    private SweetFruit sweetFruit;

    @Autowired
    @Qualifier("redApple")
    private RedApple redApple;

    @Autowired
    @Qualifier("redApple")
    private Fruit rFruit;

    @Autowired
    @Qualifier("sweetFruit")
    private Fruit sFruit;

    @Autowired
    private FruitFarmer fruitFarmer;

    @org.junit.Test
    public void test() {

    }
}

使用的測(cè)試類
SweetFruit實(shí)現(xiàn)Fruit接口。RedApple繼承SweetFruit并且實(shí)現(xiàn)Origin接口鱼鸠,并且關(guān)聯(lián)FruitWeight接口猛拴。AppleWeight實(shí)現(xiàn)FruitWeight接口。

within

package com.drw.start.boot.test;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class AopDesignator {

    @Before("within(com.drw.start.boot.test.Fruit)")
    public void withinTest(JoinPoint point) {
        System.out.println("within(com.drw.start.boot.test.Fruit) - " + point.getSignature());
    }

    @Before("within(com.drw.start.boot.test.SweetFruit)")
    public void withinTest1(JoinPoint point) {
        System.out.println("within(com.drw.start.boot.test.SweetFruit) - " + point.getSignature());
    }

    @Before("within(com.drw.start.boot.test.RedApple)")
    public void withinTest2(JoinPoint point) {
        System.out.println("within(com.drw.start.boot.test.RedApple) - " + point.getSignature());
    }

}

定義包含within指示器的切面

    @org.junit.Test
    public void test() {
        System.out.println("-------------Fruit(SweetFruit)-----------");
        sFruit.print();

        System.out.println("-------------Fruit(RedApple)-------------");
        rFruit.print();

        System.out.println("-------------SweetFruit------------------");
        sweetFruit.print();

        System.out.println("-------------RedApple--------------------");
        redApple.print();
        redApple.printOrigin();

        System.out.println("-------------FruitFarmer-----------------");
        fruitFarmer.print();
    }

測(cè)試用例

-------------Fruit(SweetFruit)-----------
within(com.drw.start.boot.test.SweetFruit) - void com.drw.start.boot.test.SweetFruit.print()
好吃的甜水果
-------------Fruit(RedApple)-------------
within(com.drw.start.boot.test.RedApple) - void com.drw.start.boot.test.RedApple.print()
好吃的紅蘋果
-------------SweetFruit------------------
within(com.drw.start.boot.test.SweetFruit) - void com.drw.start.boot.test.SweetFruit.print()
好吃的甜水果
-------------RedApple--------------------
within(com.drw.start.boot.test.RedApple) - void com.drw.start.boot.test.RedApple.print()
好吃的紅蘋果
within(com.drw.start.boot.test.RedApple) - void com.drw.start.boot.test.RedApple.printOrigin()
浙江產(chǎn)的紅蘋果
-------------FruitFarmer-----------------
種水果的農(nóng)民

within指示器用來限定連接點(diǎn)必須在確定的類型或包中蚀狰,在上面的切面中定義了Fruit愉昆、SweetFruitRedApple這三個(gè)類型麻蹋,根據(jù)輸出發(fā)現(xiàn)只有SweetFruit跛溉、RedApple這兩個(gè)切面進(jìn)行了攔截。這說明了within指示器只攔截確定的類型扮授,也就是跟它的接口無關(guān)芳室,定義什么類型就攔截什么類型。

this

package com.drw.start.boot.test;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class AopDesignator {

    @Before("this(com.drw.start.boot.test.Fruit)")
    public void thisTest(JoinPoint point) {
        System.out.println("this(com.drw.start.boot.test.Fruit) - " + point.getSignature());
    }

    @Before("this(com.drw.start.boot.test.SweetFruit)")
    public void thisTest1(JoinPoint point) {
        System.out.println("this(com.drw.start.boot.test.SweetFruit) - " + point.getSignature());
    }

    @Before("this(com.drw.start.boot.test.RedApple)")
    public void thisTest2(JoinPoint point) {
        System.out.println("this(com.drw.start.boot.test.RedApple) - " + point.getSignature());
    }

    @Before("this(com.drw.start.boot.test.Origin)")
    public void thisTest3(JoinPoint point) {
        System.out.println("this(com.drw.start.boot.test.Origin) - " + point.getSignature());
    }

}

定義包含this指示器的切面

    @org.junit.Test
    public void testThis() {
        System.out.println("-------------SweetFruit------------------");
        sweetFruit.print();

        System.out.println("-------------RedApple--------------------");
        redApple.print();
        redApple.printOrigin();

        System.out.println("-------------FruitFarmer------------------");
        fruitFarmer.print();
    }

測(cè)試用例

-------------SweetFruit------------------
this(com.drw.start.boot.test.Fruit) - void com.drw.start.boot.test.SweetFruit.print()
this(com.drw.start.boot.test.SweetFruit) - void com.drw.start.boot.test.SweetFruit.print()
好吃的甜水果
-------------RedApple--------------------
this(com.drw.start.boot.test.Fruit) - void com.drw.start.boot.test.RedApple.print()
this(com.drw.start.boot.test.SweetFruit) - void com.drw.start.boot.test.RedApple.print()
this(com.drw.start.boot.test.RedApple) - void com.drw.start.boot.test.RedApple.print()
this(com.drw.start.boot.test.Origin) - void com.drw.start.boot.test.RedApple.print()
好吃的紅蘋果
this(com.drw.start.boot.test.Fruit) - void com.drw.start.boot.test.RedApple.printOrigin()
this(com.drw.start.boot.test.SweetFruit) - void com.drw.start.boot.test.RedApple.printOrigin()
this(com.drw.start.boot.test.RedApple) - void com.drw.start.boot.test.RedApple.printOrigin()
this(com.drw.start.boot.test.Origin) - void com.drw.start.boot.test.RedApple.printOrigin()
浙江產(chǎn)的紅蘋果
-------------FruitFarmer------------------
種水果的農(nóng)民

this指示器用來限定連接點(diǎn)屬于給定類型的一個(gè)實(shí)例(代理對(duì)象)刹勃,從上面的輸出中可以看到堪侯,sweetFruit.print();this(...Fruit)this(...SweetFruit)攔截荔仁,redApple.print();redApple.printOrigin();this(...Fruit)伍宦、this(...SweetFruit)this(...RedApple)乏梁、this(...Origin)攔截次洼。這說明了不管方法是來源于哪個(gè)接口或類(redApple.printOrigin();來源于Origin接口),只要代理對(duì)象的實(shí)例屬于this中所定義的類型掌呜,那么這個(gè)方法就會(huì)被攔截滓玖。比如sweetFruit的代理對(duì)象既是Fruit的一個(gè)實(shí)例坪哄,也是SweetFruit的一個(gè)實(shí)例质蕉。redApple的代理對(duì)象分別屬于FruitSweetFruit翩肌、RedApple模暗、Origin這四個(gè)類型的一個(gè)實(shí)例。
注:我這邊的測(cè)試環(huán)境顯示AOP使用了CGLIB代理念祭,也就是繼承代理兑宇,所以代理對(duì)象同屬以上接口或類,如果使用了JDK動(dòng)態(tài)代理可能會(huì)產(chǎn)生不同的結(jié)果

target

package com.drw.start.boot.test;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class AopDesignator {

    @Before("target(com.drw.start.boot.test.Fruit)")
    public void targetTest(JoinPoint point) {
        System.out.println("target(com.drw.start.boot.test.Fruit) - " + point.getSignature());
    }

    @Before("target(com.drw.start.boot.test.SweetFruit)")
    public void targetTest1(JoinPoint point) {
        System.out.println("target(com.drw.start.boot.test.SweetFruit) - " + point.getSignature());
    }

    @Before("target(com.drw.start.boot.test.RedApple)")
    public void targetTest2(JoinPoint point) {
        System.out.println("target(com.drw.start.boot.test.RedApple) - " + point.getSignature());
    }

    @Before("target(com.drw.start.boot.test.Origin)")
    public void targetTest3(JoinPoint point) {
        System.out.println("target(com.drw.start.boot.test.Origin) - " + point.getSignature());
    }

}

定義包含target指示器的切面

    @org.junit.Test
    public void testTarget() {
        System.out.println("-------------SweetFruit------------------");
        sweetFruit.print();

        System.out.println("-------------RedApple--------------------");
        redApple.print();
        redApple.printOrigin();

        System.out.println("-------------FruitFarmer------------------");
        fruitFarmer.print();
    }

測(cè)試用例

-------------SweetFruit------------------
target(com.drw.start.boot.test.Fruit) - void com.drw.start.boot.test.SweetFruit.print()
target(com.drw.start.boot.test.SweetFruit) - void com.drw.start.boot.test.SweetFruit.print()
好吃的甜水果
-------------RedApple--------------------
target(com.drw.start.boot.test.Fruit) - void com.drw.start.boot.test.RedApple.print()
target(com.drw.start.boot.test.SweetFruit) - void com.drw.start.boot.test.RedApple.print()
target(com.drw.start.boot.test.RedApple) - void com.drw.start.boot.test.RedApple.print()
target(com.drw.start.boot.test.Origin) - void com.drw.start.boot.test.RedApple.print()
好吃的紅蘋果
target(com.drw.start.boot.test.Fruit) - void com.drw.start.boot.test.RedApple.printOrigin()
target(com.drw.start.boot.test.SweetFruit) - void com.drw.start.boot.test.RedApple.printOrigin()
target(com.drw.start.boot.test.RedApple) - void com.drw.start.boot.test.RedApple.printOrigin()
target(com.drw.start.boot.test.Origin) - void com.drw.start.boot.test.RedApple.printOrigin()
浙江產(chǎn)的紅蘋果
-------------FruitFarmer------------------
種水果的農(nóng)民

target指示器用來限定連接點(diǎn)屬于給定類型的一個(gè)實(shí)例(被代理對(duì)象)粱坤,這個(gè)指示器的語義跟this指示器是很相似的隶糕,然后從上面的輸出來看它們也是一樣的(除了指示器不同)瓷产。但是它們有一個(gè)重要的區(qū)別,this中的實(shí)例指的是代理對(duì)象枚驻,而target中的實(shí)例指的是被代理對(duì)象濒旦。

args

package com.drw.start.boot.test;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class AopDesignator {

    @Before("within(com.drw.start.boot.test.*) && args(java.lang.Integer, java.lang.String)")
    public void argsTest(JoinPoint point) {
        System.out.println("args(java.lang.Integer, java.lang.String) - " + point.getSignature());
    }
}

定義包含args指示器的切面,上面的切面表達(dá)式中額外定義了within指示器再登,這個(gè)主要是為了縮小args的使用范圍尔邓。如果不加,Spring AOP會(huì)嘗試去代理所有符合條件的對(duì)象锉矢,但是有些對(duì)象的訪問會(huì)有限制梯嗽,導(dǎo)致啟動(dòng)異常。這個(gè)也提醒我們使用AOP時(shí)必須要明確指定使用范圍沽损,否則會(huì)造成不可預(yù)料的錯(cuò)誤灯节。

   @org.junit.Test
    public void testArgs() {
        System.out.println("-------------RedApple--------------------");
        redApple.printPrice();
        redApple.printPrice(10);
        redApple.printPrice(1000, "這個(gè)蘋果價(jià)格很貴");
    }

測(cè)試用例,回顧一下之前定義的三個(gè)printPrice方法:

 public void printPrice() {
        System.out.println("紅蘋果10塊一斤");
    }

    public void printPrice(Integer price) {
        System.out.println("紅蘋果" + price + "塊一斤");
    }

    public void printPrice(Integer price, String mesg) {
        System.out.println("紅蘋果" + price + "塊一斤");
    }
-------------RedApple--------------------
紅蘋果10塊一斤
紅蘋果15塊一斤
args(java.lang.Integer, java.lang.String) - void com.drw.start.boot.test.RedApple.printPrice(Integer,String)
紅蘋果1000塊一斤

args指示器用來限定連接點(diǎn)绵估,也就是方法執(zhí)行時(shí)它的參數(shù)屬于給定類型的一個(gè)實(shí)例显晶,從上面的輸出來看,只有public void printPrice(Integer price, String mesg)這個(gè)方法被攔截壹士,因?yàn)橹挥兴蠗l件磷雇。如果我們將定義改為public void printPrice(String mesg,Integer price ),結(jié)果如下:

-------------RedApple--------------------
紅蘋果10塊一斤
紅蘋果15塊一斤
紅蘋果1000塊一斤

也就是說args指示器不但對(duì)參數(shù)類型有要求躏救,而且還會(huì)對(duì)參數(shù)個(gè)數(shù)唯笙、定義順序有要求。

@target

package com.drw.start.boot.test;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class AopDesignator {

    @Before("within(com.drw.start.boot.test.*) && @target(org.springframework.validation.annotation.Validated)")
    public void _targetTest(JoinPoint point) {
        System.out.println("@target(org.springframework.validation.annotation.Validated) - " + point.getSignature());
    }

}

定義包含@target指示器的切面

    @org.junit.Test
    public void test_target() {
        System.out.println("-------------RedApple--------------------");
        redApple.print();

        System.out.println("-------------FruitFarmer------------------");
        fruitFarmer.print();
    }

測(cè)試用例盒使,然后回顧一下之前定義的RedApple這個(gè)類上所注解的@Validated

@Component
@Validated
public class RedApple extends SweetFruit implements Origin {
...
}
-------------RedApple--------------------
@target(org.springframework.validation.annotation.Validated) - void com.drw.start.boot.test.RedApple.print()
好吃的紅蘋果
-------------FruitFarmer------------------
種水果的農(nóng)民

現(xiàn)在刪除RedApple上的@Validated注解崩掘,將這個(gè)注解放到SweetFruit上,輸出如下:

-------------RedApple--------------------
好吃的紅蘋果
-------------FruitFarmer------------------
種水果的農(nóng)民

重復(fù)以上步驟少办,將@Validated注解放到Fruit接口上苞慢,輸出如下:

-------------RedApple--------------------
好吃的紅蘋果
-------------FruitFarmer------------------
種水果的農(nóng)民

@target用來限定連接點(diǎn)屬于一個(gè)執(zhí)行對(duì)象(被代理對(duì)象)所屬的擁有給定注解的類。雖然@targettarget名稱相似英妓,但是它們用法是完全不同的挽放,前者針對(duì)注解,后置針對(duì)類型蔓纠。另外從上面的輸出可以看出@target限定在一個(gè)執(zhí)行對(duì)象的所屬類辑畦,與它的父類接口無關(guān)。

@within

package com.drw.start.boot.test;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class AopDesignator {

    @Before("within(com.drw.start.boot.test.*) && @within(org.springframework.validation.annotation.Validated)")
    public void _withinTest(JoinPoint point) {
        System.out.println("@within(org.springframework.validation.annotation.Validated) - " + point.getSignature());
    }

}

定義包含@within指示器的切面

    @org.junit.Test
    public void test_within() {
        System.out.println("-------------RedApple--------------------");
        redApple.print();
        redApple.print(11);

        System.out.println("-------------FruitFarmer------------------");
        fruitFarmer.print();
    }

測(cè)試用例腿倚,然后注意redApple.print(11);它是定義在SweetFruit類中

-------------RedApple--------------------
@within(org.springframework.validation.annotation.Validated) - void com.drw.start.boot.test.RedApple.print()
好吃的紅蘋果
好吃的甜水果11
-------------FruitFarmer------------------
種水果的農(nóng)民

現(xiàn)在刪除RedApple上的@Validated注解纯出,將這個(gè)注解放到SweetFruit上,輸出如下:

-------------RedApple--------------------
好吃的紅蘋果
@within(org.springframework.validation.annotation.Validated) - void com.drw.start.boot.test.SweetFruit.print(int)
好吃的甜水果11
-------------FruitFarmer------------------
種水果的農(nóng)民

重復(fù)以上步驟,將@Validated注解放到Fruit接口上暂筝,輸出如下:

-------------RedApple--------------------
好吃的紅蘋果
好吃的甜水果11
-------------FruitFarmer------------------
種水果的農(nóng)民

@within用來限定連接點(diǎn)屬于擁有給定注解的類型中箩言。從上面的輸出可以看出,@target針對(duì)執(zhí)行對(duì)象所屬的類焕襟,而@within針對(duì)執(zhí)行對(duì)象所屬的類型分扎。另外所執(zhí)行的方法必須屬于擁有給定注解的類型中,比如redApple.print();被重寫在RedApple類中胧洒,redApple.print(11);被定義在SweetFruit類中畏吓,當(dāng)這兩個(gè)類擁有指定注解后方法執(zhí)行時(shí)才會(huì)被攔截。最后需要注意的是@withinwithin只是名稱接近卫漫,實(shí)際使用效果是不同的菲饼。

@args

package com.drw.start.boot.test;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class AopDesignator {

    @Before("within(com.drw.start.boot.test.*) && @args(com.fasterxml.jackson.databind.annotation.JsonDeserialize)")
    public void _argsTest(JoinPoint point) {
        System.out.println("@args(com.fasterxml.jackson.databind.annotation.JsonDeserialize) - " + point.getSignature());
    }

}

定義包含@args指示器的切面

    @org.junit.Test
    public void test_args() {
        System.out.println("-------------RedApple--------------------");
        redApple.printPrice(100);
        FruitWeight fruitWeight = new AppleWeight(500);

        redApple.printWeight(fruitWeight);
    }

測(cè)試用例,回顧一下在RedApple中定義的方法以及FruitWeight接口的定義:

...
public void printPrice(Integer price) {
        System.out.println("紅蘋果" + price + "塊一斤");
}
...

****************************************************
package com.drw.start.boot.test;

public interface FruitWeight {

    public int getWeight();
}

****************************************************
package com.drw.start.boot.test;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;

@JsonDeserialize
public class AppleWeight implements FruitWeight {

    public int weight;

    public AppleWeight(int weight) {
        this.weight = weight;
    }

    @Override
    public int getWeight() {
        return weight;
    }

}
-------------RedApple--------------------
紅蘋果100塊一斤
@args(com.fasterxml.jackson.databind.annotation.JsonDeserialize) - void com.drw.start.boot.test.RedApple.printWeight(FruitWeight)
這個(gè)蘋果500克

現(xiàn)在刪除AppleWeight上的@JsonDeserialize注解列赎,將這個(gè)注解放到FruitWeight上宏悦,輸出如下:

-------------RedApple--------------------
紅蘋果100塊一斤
@args(com.fasterxml.jackson.databind.annotation.JsonDeserialize) - void com.drw.start.boot.test.RedApple.printWeight(FruitWeight)
這個(gè)蘋果500克

現(xiàn)在將@JsonDeserialize注解放到AppleWeight上,并且再定義一個(gè)繼承了AppleWeight的子類:

package com.drw.start.boot.test;

public class RedAppleWeight extends AppleWeight {

    public RedAppleWeight(int weight) {
        super(weight);
    }

}
   @org.junit.Test
    public void test_args() {
        System.out.println("-------------RedApple--------------------");
        redApple.printPrice(100);
        FruitWeight fruitWeight = new AppleWeight(500);

        FruitWeight redAppleWeight = new RedAppleWeight(200);

        redApple.printWeight(fruitWeight);

        redApple.printWeight(redAppleWeight);
    }

測(cè)試用例

-------------RedApple--------------------
紅蘋果100塊一斤
@args(com.fasterxml.jackson.databind.annotation.JsonDeserialize) - void com.drw.start.boot.test.RedApple.printWeight(FruitWeight)
這個(gè)蘋果500克
這個(gè)蘋果200克

@args用來限定連接點(diǎn)包吝,方法執(zhí)行時(shí)傳遞的參數(shù)的運(yùn)行時(shí)類型擁有給定注解饼煞。根據(jù)以上的輸出以及@args的定義,這個(gè)給定的注解要么定義在方法參數(shù)的類型本身上诗越,那么定義在的它的實(shí)現(xiàn)類上砖瞧。比如RedAppleWeight它雖然繼承了AppleWeight(擁有指定注解),但是它本身沒有指定注解嚷狞,并且當(dāng)FruitWeight也沒有指定注解時(shí)块促,相關(guān)方法不會(huì)被攔截。

@annotation

package com.drw.start.boot.test;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class AopDesignator {

    @Before("within(com.drw.start.boot.test.*) && @annotation(com.fasterxml.jackson.databind.annotation.JsonSerialize)")
    public void _annotationTest(JoinPoint point) {
        System.out.println("@annotation(com.fasterxml.jackson.databind.annotation.JsonSerialize) - " + point.getSignature());
    }

}

定義包含@annotation指示器的切面

    @org.junit.Test
    public void test_annotation() {
        System.out.println("-------------FruitFarmer------------------");
        fruitFarmer.print();
        fruitFarmer.worker();
    }

測(cè)試用例床未,回顧一下FruitFarmer的定義:

package com.drw.start.boot.test;

import org.springframework.stereotype.Component;

import com.fasterxml.jackson.databind.annotation.JsonSerialize;

@Component
public class FruitFarmer {

    @JsonSerialize
    public void print() {
        System.out.println("種水果的農(nóng)民");
    }

    @JsonSerialize
    public void worker() {
        System.out.println("果農(nóng)在勞動(dòng)");
    }
}
-------------FruitFarmer------------------
@annotation(com.fasterxml.jackson.databind.annotation.JsonSerialize) - void com.drw.start.boot.test.FruitFarmer.print()
種水果的農(nóng)民
@annotation(com.fasterxml.jackson.databind.annotation.JsonSerialize) - void com.drw.start.boot.test.FruitFarmer.worker()
果農(nóng)在勞動(dòng)

現(xiàn)在刪除print()上的@JsonSerialize注解竭翠,輸出如下:

-------------FruitFarmer------------------
種水果的農(nóng)民
@annotation(com.fasterxml.jackson.databind.annotation.JsonSerialize) - void com.drw.start.boot.test.FruitFarmer.worker()
果農(nóng)在勞動(dòng)

@annotation用來限定連接點(diǎn)的方法擁有給定注解。這個(gè)指示器比較容易理解薇搁,就是目標(biāo)方法上擁有給定注解就可以了斋扰。

參考資源

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市啃洋,隨后出現(xiàn)的幾起案子传货,更是在濱河造成了極大的恐慌,老刑警劉巖裂允,帶你破解...
    沈念sama閱讀 222,183評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件损离,死亡現(xiàn)場(chǎng)離奇詭異哥艇,居然都是意外死亡绝编,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來十饥,“玉大人窟勃,你說我怎么就攤上這事《憾拢” “怎么了秉氧?”我有些...
    開封第一講書人閱讀 168,766評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)蜒秤。 經(jīng)常有香客問我汁咏,道長(zhǎng),這世上最難降的妖魔是什么作媚? 我笑而不...
    開封第一講書人閱讀 59,854評(píng)論 1 299
  • 正文 為了忘掉前任攘滩,我火速辦了婚禮,結(jié)果婚禮上纸泡,老公的妹妹穿的比我還像新娘漂问。我一直安慰自己,他們只是感情好女揭,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評(píng)論 6 398
  • 文/花漫 我一把揭開白布蚤假。 她就那樣靜靜地躺著,像睡著了一般吧兔。 火紅的嫁衣襯著肌膚如雪磷仰。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,457評(píng)論 1 311
  • 那天境蔼,我揣著相機(jī)與錄音芒划,去河邊找鬼。 笑死欧穴,一個(gè)胖子當(dāng)著我的面吹牛民逼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播涮帘,決...
    沈念sama閱讀 40,999評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼拼苍,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了调缨?” 一聲冷哼從身側(cè)響起疮鲫,我...
    開封第一講書人閱讀 39,914評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎弦叶,沒想到半個(gè)月后俊犯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,465評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡伤哺,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評(píng)論 3 342
  • 正文 我和宋清朗相戀三年燕侠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了者祖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,675評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡绢彤,死狀恐怖七问,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情茫舶,我是刑警寧澤械巡,帶...
    沈念sama閱讀 36,354評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站饶氏,受9級(jí)特大地震影響讥耗,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜疹启,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評(píng)論 3 335
  • 文/蒙蒙 一葛账、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧皮仁,春花似錦籍琳、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至势誊,卻和暖如春呜达,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背粟耻。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工查近, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人挤忙。 一個(gè)月前我還...
    沈念sama閱讀 49,091評(píng)論 3 378
  • 正文 我出身青樓霜威,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親册烈。 傳聞我的和親對(duì)象是個(gè)殘疾皇子戈泼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評(píng)論 2 360

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