spring aop中pointcut表達式完整版


spring aop中pointcut表達式完整版

本文主要介紹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表達式

攔截任意公共方法

execution(public * *(..))

攔截以set開頭的任意方法

execution(* set*(..))

攔截類或者接口中的方法

execution(* com.xyz.service.AccountService.*(..))

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

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

execution(* com.xyz.service.*.*(..))

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

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

execution(* com.xyz.service..*.*(..))

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

2.within表達式

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

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

within(com.xyz.service.*)

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

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

within(com.xyz.service..*)

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

3.this表達式

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

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

this(com.xyz.service.AccountService)

示例

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

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.1.4.RELEASE</version>
      <relativePath/> <!-- lookup parent from repository -->
   </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>
package com.ms.aop.jthis.demo1;

public interface IService {
    void m1();
}
package com.ms.aop.jthis.demo1;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class ServiceImpl implements IService {
    @Override
    public void m1() {
        log.info("切入點this測試!");
    }
}
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
@Slf4j
public 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;
    }
}
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
@Slf4j
public 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);
    }
}

執行結果

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
  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)
    

    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表達式

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

target(com.xyz.service.AccountService)

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

示例

package com.ms.aop.target;

public interface IService {
    void m1();
}
package com.ms.aop.target;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class ServiceImpl implements IService {
    @Override
    public void m1() {
        log.info("切入點target測試!");
    }
}
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
@Slf4j
public 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;
    }
}
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})
@EnableAspectJAutoProxy
public class Client {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Client.class);
        IService service = annotationConfigApplicationContext.getBean(IService.class);
        service.m1();
    }
}

執行結果:

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 - 方法執行完畢

this 和 target 的不同點

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

5.args 表達式

匹配方法中的參數

@Pointcut("args(com.ms.aop.args.demo1.UserModel)")

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

匹配多個參數

args(type1,type2,typeN)

匹配任意多個參數

@Pointcut("args(com.ms.aop.args.demo1.UserModel,..)")

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

6.@target表達式

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

@target(com.ms.aop.jtarget.Annotation1)

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

7.@within表達式

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

@within(com.ms.aop.jwithin.Annotation1)

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

@target 和 @within 的不同點

  1. @target(注解A):判斷被調用的目標對象中是否聲明了注解A,如果有,會被攔截

  2. @within(注解A): 判斷被調用的方法所屬的類中是否聲明了注解A,如果有,會被攔截

  3. @target關注的是被調用的對象,@within關注的是調用的方法所在的類

8.@annotation表達式

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

@annotation(com.ms.aop.jannotation.demo2.Annotation1)

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

9.@args表達式

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

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

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM