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
愉昆、SweetFruit
、RedApple
這三個(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ì)象分別屬于Fruit
、SweetFruit
翩肌、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ì)象)所屬的擁有給定注解的類。雖然@target
和target
名稱相似英妓,但是它們用法是完全不同的挽放,前者針對(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ì)被攔截。最后需要注意的是@within
和within
只是名稱接近卫漫,實(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)方法上擁有給定注解就可以了斋扰。
參考資源