spring aop中pointcut表達式完整版
本文主要介紹spring aop中9種切入點表達式的寫法
- execute
- within
- this
- target
- args
- @target
- @within
- @annotation
- @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
-
@EnableAspectJAutoProxy:表示若spring創建的對象如果實現了接口,默認使用jdk動態代理,如果沒有實現接口,使用cglib創建代理對象
-
所以 service 是使用jdk動態代理生成的對象,service instanceof ServiceImpl 為 false
-
@Pointcut("this(com.ms.aop.jthis.demo1.ServiceImpl)")表示被spring代理之后生成的對象必須為com.ms.aop.jthis.demo1.ServiceImpl才會被攔截,但是service不是ServiceImpl類型的對象了,所以不會被攔截
-
修改代碼
@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 的不同點
- this作用於代理對象,target作用於目標對象
- this表示目標對象被代理之后生成的代理對象和指定的類型匹配會被攔截,匹配的是代理對象
- 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 的不同點
-
@target(注解A):判斷被調用的目標對象中是否聲明了注解A,如果有,會被攔截
-
@within(注解A): 判斷被調用的方法所屬的類中是否聲明了注解A,如果有,會被攔截
-
@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,..)