必備技能:spring aop 切入點表達式,你都會麼?

本文主要介紹spring aop中9種切入點表達式的寫法

  1. execute
  2. within
  3. this
  4. target
  5. args
  6. @target
  7. @within
  8. @annotation
  9. @args


0. 示例代碼git地址

https://gitee.com/likun_557/spring-aop-demo


1.execute表達式

攔截任意公共方法

<code>execution(public * *(..))/<code>

攔截以set開頭的任意方法

<code>execution(* set*(..))/<code>

攔截類或者接口中的方法

<code>execution(* com.xyz.service.AccountService.*(..))/<code>

攔截AccountService(類、接口)中定義的所有方法

攔截包中定義的方法,不包含子包中的方法

<code>execution(* com.xyz.service.*.*(..))/<code>

攔截com.xyz.service包中所有類中任意方法,不包含子包中的類

攔截包或者子包中定義的方法

<code>execution(* com.xyz.service..*.*(..))/<code>

攔截com.xyz.service包或者子包中定義的所有方法


2.within表達式

表達式格式:包名.* 或者 包名..*

攔截包中任意方法,不包含子包中的方法

<code>within(com.xyz.service.*)/<code>

攔截service包中任意類的任意方法

攔截包或者子包中定義的方法

<code>within(com.xyz.service..*)/<code>

攔截service包及子包中任意類的任意方法


3.this表達式

代理對象為指定的類型會被攔截

目標對象使用aop之後生成的代理對象必須是指定的類型才會被攔截,注意是目標對象被代理之後生成的代理對象和指定的類型匹配才會被攔截

<code>this(com.xyz.service.AccountService)/<code>

示例

this表達式的使用,可能不是很好理解,用示例說明一下:

<code><project>   <modelversion>4.0.0/<modelversion>   <parent>      <groupid>org.springframework.boot/<groupid>      <artifactid>spring-boot-starter-parent/<artifactid>      <version>2.1.4.RELEASE/<version>      <relativepath>    /<parent>   <groupid>com.ms/<groupid>   <artifactid>spring-aop-demo/<artifactid>   <version>0.0.1-SNAPSHOT/<version>   <name>spring-aop-demo/<name>   <description>Demo project for Spring Boot/<description>   <properties>      <java.version>1.8/<java.version>   /<properties>   <dependencies>      <dependency>         <groupid>org.springframework.boot/<groupid>         <artifactid>spring-boot-starter-aop/<artifactid>      /<dependency>      <dependency>         <groupid>org.projectlombok/<groupid>         <artifactid>lombok/<artifactid>      /<dependency>      <dependency>         <groupid>org.springframework.boot/<groupid>         <artifactid>spring-boot-starter-test/<artifactid>         <scope>test/<scope>      /<dependency>   /<dependencies>   <build>      <plugins>         <plugin>            <groupid>org.springframework.boot/<groupid>            <artifactid>spring-boot-maven-plugin/<artifactid>         /<plugin>      /<plugins>   /<build>/<project>/<code>
<code>package com.ms.aop.jthis.demo1;public interface IService {    void m1();}/<code>
<code>package com.ms.aop.jthis.demo1;import lombok.extern.slf4j.Slf4j;import org.springframework.stereotype.Component;@Slf4j@Componentpublic class ServiceImpl implements IService {    @Override    public void m1() {        log.info("切入點this測試!");    }}/<code>
<code>package com.ms.aop.jthis.demo1;import lombok.extern.slf4j.Slf4j;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.springframework.stereotype.Component;@Aspect@Component@Slf4jpublic class Interceptor1 {    @Pointcut("this(com.ms.aop.jthis.demo1.ServiceImpl)")    public void pointcut() {    }    @Around("pointcut()")    public Object invoke(ProceedingJoinPoint invocation) throws Throwable {        log.info("方法執行之前");        Object result = invocation.proceed();        log.info("方法執行完畢");        return result;    }}/<code>
<code>package com.ms.aop.jthis.demo1;import lombok.extern.slf4j.Slf4j;import org.springframework.context.annotation.AnnotationConfigApplicationContext;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.EnableAspectJAutoProxy;@ComponentScan(basePackageClasses = {Client.class})@EnableAspectJAutoProxy@Slf4jpublic class Client {    public static void main(String[] args) {        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Client.class);        IService service = annotationConfigApplicationContext.getBean(IService.class);        service.m1();        log.info("{}", service instanceof ServiceImpl);    }}/<code>


執行結果

<code>10:27:12.277 [main] INFO com.ms.aop.jthis.demo1.ServiceImpl - 切入點this測試!10:27:12.277 [main] INFO com.ms.aop.jthis.demo1.Client - false/<code>
  1. @EnableAspectJAutoProxy:表示若spring創建的對象如果實現了接口,默認使用jdk動態代理,如果沒有實現接口,使用cglib創建代理對象
  2. 所以 service 是使用jdk動態代理生成的對象,service instanceof ServiceImplfalse
  3. @Pointcut("this(com.ms.aop.jthis.demo1.ServiceImpl)")表示被spring代理之後生成的對象必須為com.ms.aop.jthis.demo1.ServiceImpl才會被攔截,但是service不是ServiceImpl類型的對象了,所以不會被攔截
  4. 修改代碼@EnableAspectJAutoProxy(proxyTargetClass=true),使用cglib來生成代理對象

執行結果:

10:34:50.736[main]INFO com.ms.aop.jthis.demo1.Interceptor1-方法執行之前

10:34:50.755[main]INFO com.ms.aop.jthis.demo1.ServiceImpl-切入點this測試!

10:34:50.756[main]INFO com.ms.aop.jthis.demo1.Interceptor1-方法執行完畢

10:34:50.756[main]INFO com.ms.aop.jthis.demo1.Client-true

service 為 ServiceImpl類型的對象,所以會被攔截


4.target表達式

目標對象為指定的類型被攔截

<code>target(com.xyz.service.AccountService)/<code>

目標對象為AccountService類型的會被代理

示例

<code>package com.ms.aop.target;public interface IService {    void m1();}/<code>
<code>package com.ms.aop.target;import lombok.extern.slf4j.Slf4j;import org.springframework.stereotype.Component;@Slf4j@Componentpublic class ServiceImpl implements IService {    @Override    public void m1() {        log.info("切入點target測試!");    }}/<code>
<code>package com.ms.aop.target;import lombok.extern.slf4j.Slf4j;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.springframework.stereotype.Component;@Aspect@Component@Slf4jpublic class Interceptor1 {    @Pointcut("target(com.ms.aop.target.ServiceImpl)")    public void pointcut() {    }    @Around("pointcut()")    public Object invoke(ProceedingJoinPoint invocation) throws Throwable {        log.info("方法執行之前");        Object result = invocation.proceed();        log.info("方法執行完畢");        return result;    }}/<code>
<code>package com.ms.aop.target;import org.springframework.context.annotation.AnnotationConfigApplicationContext;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.EnableAspectJAutoProxy;@ComponentScan(basePackageClasses = {Client.class})@EnableAspectJAutoProxypublic class Client {    public static void main(String[] args) {        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Client.class);        IService service = annotationConfigApplicationContext.getBean(IService.class);        service.m1();    }}/<code>

執行結果:

<code>10:49:01.674 [main] INFO com.ms.aop.target.Interceptor1 - 方法執行之前10:49:01.674 [main] INFO com.ms.aop.target.ServiceImpl - 切入點target測試!10:49:01.674 [main] INFO com.ms.aop.target.Interceptor1 - 方法執行完畢/<code>

this 和 target 的不同點

  1. this作用於代理對象,target作用於目標對象
  2. this表示目標對象被代理之後生成的代理對象和指定的類型匹配會被攔截,匹配的是代理對象
  3. target表示目標對象和指定的類型匹配會被攔截,匹配的是目標對象


5.args 表達式

匹配方法中的參數

<code>@Pointcut("args(com.ms.aop.args.demo1.UserModel)")/<code>

匹配只有一個參數,且類型為com.ms.aop.args.demo1.UserModel

匹配多個參數

<code>args(type1,type2,typeN)/<code>

匹配任意多個參數

<code>@Pointcut("args(com.ms.aop.args.demo1.UserModel,..)")/<code>

匹配第一個參數類型為com.ms.aop.args.demo1.UserModel的所有方法, .. 表示任意個參數


6.@target表達式

匹配的目標對象的類有一個指定的註解

<code>@target(com.ms.aop.jtarget.Annotation1)/<code>

目標對象中包含com.ms.aop.jtarget.Annotation1註解,調用該目標對象的任意方法都會被攔截


7.@within表達式

指定匹配必須包含某個註解的類裡的所有連接點

<code>@within(com.ms.aop.jwithin.Annotation1)/<code>

聲明有com.ms.aop.jwithin.Annotation1註解的類中的所有方法都會被攔截

@target 和 @within 的不同點

  1. @target(註解A):判斷被調用的目標對象中是否聲明瞭註解A,如果有,會被攔截
  2. @within(註解A): 判斷被調用的方法所屬的類中是否聲明瞭註解A,如果有,會被攔截
  3. @target關注的是被調用的對象,@within關注的是調用的方法所在的類


8.@annotation表達式

匹配有指定註解的方法(註解作用在方法上面)

<code>@annotation(com.ms.aop.jannotation.demo2.Annotation1)/<code>

被調用的方法包含指定的註解


9.@args表達式

方法參數所屬的類型上有指定的註解,被匹配

注意:是方法參數所屬的類型上有指定的註解,不是方法參數中有註解

  • 匹配1個參數,且第1個參數所屬的類中有Anno1註解
<code>@args(com.ms.aop.jargs.demo1.Anno1)/<code>
  • 匹配多個參數,且多個參數所屬的類型上都有指定的註解
<code>@args(com.ms.aop.jargs.demo1.Anno1,com.ms.aop.jargs.demo1.Anno2)/<code>
  • 匹配多個參數,且第一個參數所屬的類中有Anno1註解
<code>@args(com.ms.aop.jargs.demo2.Anno1,..)/<code>


【有問題的朋友可以留言,我們一起交流學習!喜歡的請關注一下,幫忙轉發一下,謝謝!】

本文主要介紹spring aop中9種切入點表達式的寫法

  1. execute
  2. within
  3. this
  4. target
  5. args
  6. @target
  7. @within
  8. @annotation
  9. @args


0. 示例代碼git地址

https://gitee.com/likun_557/spring-aop-demo


1.execute表達式

攔截任意公共方法

<code>execution(public * *(..))/<code>

攔截以set開頭的任意方法

<code>execution(* set*(..))/<code>

攔截類或者接口中的方法

<code>execution(* com.xyz.service.AccountService.*(..))/<code>

攔截AccountService(類、接口)中定義的所有方法

攔截包中定義的方法,不包含子包中的方法

<code>execution(* com.xyz.service.*.*(..))/<code>

攔截com.xyz.service包中所有類中任意方法,不包含子包中的類

攔截包或者子包中定義的方法

<code>execution(* com.xyz.service..*.*(..))/<code>

攔截com.xyz.service包或者子包中定義的所有方法


2.within表達式

表達式格式:包名.* 或者 包名..*

攔截包中任意方法,不包含子包中的方法

<code>within(com.xyz.service.*)/<code>

攔截service包中任意類的任意方法

攔截包或者子包中定義的方法

<code>within(com.xyz.service..*)/<code>

攔截service包及子包中任意類的任意方法


3.this表達式

代理對象為指定的類型會被攔截

目標對象使用aop之後生成的代理對象必須是指定的類型才會被攔截,注意是目標對象被代理之後生成的代理對象和指定的類型匹配才會被攔截

<code>this(com.xyz.service.AccountService)/<code>

示例

this表達式的使用,可能不是很好理解,用示例說明一下:

<code><project>   <modelversion>4.0.0/<modelversion>   <parent>      <groupid>org.springframework.boot/<groupid>      <artifactid>spring-boot-starter-parent/<artifactid>      <version>2.1.4.RELEASE/<version>      <relativepath>    /<parent>   <groupid>com.ms/<groupid>   <artifactid>spring-aop-demo/<artifactid>   <version>0.0.1-SNAPSHOT/<version>   <name>spring-aop-demo/<name>   <description>Demo project for Spring Boot/<description>   <properties>      <java.version>1.8/<java.version>   /<properties>   <dependencies>      <dependency>         <groupid>org.springframework.boot/<groupid>         <artifactid>spring-boot-starter-aop/<artifactid>      /<dependency>      <dependency>         <groupid>org.projectlombok/<groupid>         <artifactid>lombok/<artifactid>      /<dependency>      <dependency>         <groupid>org.springframework.boot/<groupid>         <artifactid>spring-boot-starter-test/<artifactid>         <scope>test/<scope>      /<dependency>   /<dependencies>   <build>      <plugins>         <plugin>            <groupid>org.springframework.boot/<groupid>            <artifactid>spring-boot-maven-plugin/<artifactid>         /<plugin>      /<plugins>   /<build>/<project>/<code>
<code>package com.ms.aop.jthis.demo1;public interface IService {    void m1();}/<code>
<code>package com.ms.aop.jthis.demo1;import lombok.extern.slf4j.Slf4j;import org.springframework.stereotype.Component;@Slf4j@Componentpublic class ServiceImpl implements IService {    @Override    public void m1() {        log.info("切入點this測試!");    }}/<code>
<code>package com.ms.aop.jthis.demo1;import lombok.extern.slf4j.Slf4j;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.springframework.stereotype.Component;@Aspect@Component@Slf4jpublic class Interceptor1 {    @Pointcut("this(com.ms.aop.jthis.demo1.ServiceImpl)")    public void pointcut() {    }    @Around("pointcut()")    public Object invoke(ProceedingJoinPoint invocation) throws Throwable {        log.info("方法執行之前");        Object result = invocation.proceed();        log.info("方法執行完畢");        return result;    }}/<code>
<code>package com.ms.aop.jthis.demo1;import lombok.extern.slf4j.Slf4j;import org.springframework.context.annotation.AnnotationConfigApplicationContext;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.EnableAspectJAutoProxy;@ComponentScan(basePackageClasses = {Client.class})@EnableAspectJAutoProxy@Slf4jpublic class Client {    public static void main(String[] args) {        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Client.class);        IService service = annotationConfigApplicationContext.getBean(IService.class);        service.m1();        log.info("{}", service instanceof ServiceImpl);    }}/<code>

執行結果

<code>10:27:12.277 [main] INFO com.ms.aop.jthis.demo1.ServiceImpl - 切入點this測試!10:27:12.277 [main] INFO com.ms.aop.jthis.demo1.Client - false/<code>
  1. @EnableAspectJAutoProxy:表示若spring創建的對象如果實現了接口,默認使用jdk動態代理,如果沒有實現接口,使用cglib創建代理對象
  2. 所以 service 是使用jdk動態代理生成的對象,service instanceof ServiceImplfalse
  3. @Pointcut("this(com.ms.aop.jthis.demo1.ServiceImpl)")表示被spring代理之後生成的對象必須為com.ms.aop.jthis.demo1.ServiceImpl才會被攔截,但是service不是ServiceImpl類型的對象了,所以不會被攔截
  4. 修改代碼@EnableAspectJAutoProxy(proxyTargetClass=true),使用cglib來生成代理對象

執行結果:

10:34:50.736[main]INFO com.ms.aop.jthis.demo1.Interceptor1-方法執行之前

10:34:50.755[main]INFO com.ms.aop.jthis.demo1.ServiceImpl-切入點this測試!

10:34:50.756[main]INFO com.ms.aop.jthis.demo1.Interceptor1-方法執行完畢

10:34:50.756[main]INFO com.ms.aop.jthis.demo1.Client-true

service 為 ServiceImpl類型的對象,所以會被攔截


4.target表達式

目標對象為指定的類型被攔截

<code>target(com.xyz.service.AccountService)/<code>

目標對象為AccountService類型的會被代理

示例

<code>package com.ms.aop.target;public interface IService {    void m1();}/<code>
<code>package com.ms.aop.target;import lombok.extern.slf4j.Slf4j;import org.springframework.stereotype.Component;@Slf4j@Componentpublic class ServiceImpl implements IService {    @Override    public void m1() {        log.info("切入點target測試!");    }}/<code>
<code>package com.ms.aop.target;import lombok.extern.slf4j.Slf4j;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.springframework.stereotype.Component;@Aspect@Component@Slf4jpublic class Interceptor1 {    @Pointcut("target(com.ms.aop.target.ServiceImpl)")    public void pointcut() {    }    @Around("pointcut()")    public Object invoke(ProceedingJoinPoint invocation) throws Throwable {        log.info("方法執行之前");        Object result = invocation.proceed();        log.info("方法執行完畢");        return result;    }}/<code>
<code>package com.ms.aop.target;import org.springframework.context.annotation.AnnotationConfigApplicationContext;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.EnableAspectJAutoProxy;@ComponentScan(basePackageClasses = {Client.class})@EnableAspectJAutoProxypublic class Client {    public static void main(String[] args) {        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Client.class);        IService service = annotationConfigApplicationContext.getBean(IService.class);        service.m1();    }}/<code>

執行結果:

<code>10:49:01.674 [main] INFO com.ms.aop.target.Interceptor1 - 方法執行之前10:49:01.674 [main] INFO com.ms.aop.target.ServiceImpl - 切入點target測試!10:49:01.674 [main] INFO com.ms.aop.target.Interceptor1 - 方法執行完畢/<code>

this 和 target 的不同點

  1. this作用於代理對象,target作用於目標對象
  2. this表示目標對象被代理之後生成的代理對象和指定的類型匹配會被攔截,匹配的是代理對象
  3. target表示目標對象和指定的類型匹配會被攔截,匹配的是目標對象


5.args 表達式

匹配方法中的參數

<code>@Pointcut("args(com.ms.aop.args.demo1.UserModel)")/<code>

匹配只有一個參數,且類型為com.ms.aop.args.demo1.UserModel

匹配多個參數

<code>args(type1,type2,typeN)/<code>

匹配任意多個參數

<code>@Pointcut("args(com.ms.aop.args.demo1.UserModel,..)")/<code>

匹配第一個參數類型為com.ms.aop.args.demo1.UserModel的所有方法, .. 表示任意個參數


6.@target表達式

匹配的目標對象的類有一個指定的註解

<code>@within(com.ms.aop.jwithin.Annotation1)/<code>

目標對象中包含com.ms.aop.jtarget.Annotation1註解,調用該目標對象的任意方法都會被攔截


7.@within表達式

指定匹配必須包含某個註解的類裡的所有連接點

<code>@within(com.ms.aop.jwithin.Annotation1)/<code>

聲明有com.ms.aop.jwithin.Annotation1註解的類中的所有方法都會被攔截

@target 和 @within 的不同點

  1. @target(註解A):判斷被調用的目標對象中是否聲明瞭註解A,如果有,會被攔截
  2. @within(註解A): 判斷被調用的方法所屬的類中是否聲明瞭註解A,如果有,會被攔截
  3. @target關注的是被調用的對象,@within關注的是調用的方法所在的類


8.@annotation表達式

匹配有指定註解的方法(註解作用在方法上面)

<code>@annotation(com.ms.aop.jannotation.demo2.Annotation1)/<code>

被調用的方法包含指定的註解


9.@args表達式

方法參數所屬的類型上有指定的註解,被匹配

注意:是方法參數所屬的類型上有指定的註解,不是方法參數中有註解

  • 匹配1個參數,且第1個參數所屬的類中有Anno1註解
<code>@args(com.ms.aop.jargs.demo1.Anno1)/<code>
  • 匹配多個參數,且多個參數所屬的類型上都有指定的註解
<code>@args(com.ms.aop.jargs.demo1.Anno1,com.ms.aop.jargs.demo1.Anno2)/<code>
  • 匹配多個參數,且第一個參數所屬的類中有Anno1註解
<code>@args(com.ms.aop.jargs.demo2.Anno1,..)/<code>


覺得本篇文章給你帶來了幫助的,可以收藏關注一下,幫忙轉發一下讓更多的朋友來學習下哦~

另外,私信我回復“架構資料”即可得到學習資源的獲取方式哈!


分享到:


相關文章: